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
|
@@ -29,11 +29,21 @@ from typing import Iterator
|
|
|
29
29
|
|
|
30
30
|
import psutil
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
# Public override retained for tests and embedders. ``None`` means resolve the
|
|
33
|
+
# lock dynamically so a long-lived process can switch canonical namespaces
|
|
34
|
+
# without retaining the first root it observed.
|
|
35
|
+
RAM_LOCK_PATH: Path | None = None
|
|
34
36
|
MIN_FREE_MB: int = 400
|
|
35
37
|
|
|
36
38
|
|
|
39
|
+
def _ram_lock_path() -> Path:
|
|
40
|
+
if RAM_LOCK_PATH is not None:
|
|
41
|
+
return RAM_LOCK_PATH
|
|
42
|
+
from superlocalmemory.infra.data_root import state_path
|
|
43
|
+
|
|
44
|
+
return state_path("ram_lock.sem")
|
|
45
|
+
|
|
46
|
+
|
|
37
47
|
@contextmanager
|
|
38
48
|
def ram_reservation(
|
|
39
49
|
name: str,
|
|
@@ -72,15 +82,16 @@ def ram_reservation(
|
|
|
72
82
|
f"{floor_mb}MB"
|
|
73
83
|
)
|
|
74
84
|
|
|
75
|
-
|
|
85
|
+
lock_path = _ram_lock_path()
|
|
86
|
+
lock_path.parent.mkdir(parents=True, exist_ok=True)
|
|
76
87
|
# SEC-M6 — tighten the parent dir so the audit marker (``{pid}:{name}``)
|
|
77
88
|
# is not readable by other UIDs on shared hosts. Idempotent; POSIX-only.
|
|
78
89
|
try:
|
|
79
90
|
if os.name == "posix":
|
|
80
|
-
os.chmod(
|
|
91
|
+
os.chmod(lock_path.parent, 0o700)
|
|
81
92
|
except OSError: # pragma: no cover — perms race
|
|
82
93
|
pass
|
|
83
|
-
fd = os.open(str(
|
|
94
|
+
fd = os.open(str(lock_path), os.O_CREAT | os.O_RDWR, 0o600)
|
|
84
95
|
try:
|
|
85
96
|
deadline = time.time() + timeout_s
|
|
86
97
|
while True:
|
|
@@ -97,7 +97,7 @@ class LayeredRateLimiter:
|
|
|
97
97
|
for k in [p for p, e in self._per_pid.items() if e.last_used < cutoff]:
|
|
98
98
|
del self._per_pid[k]
|
|
99
99
|
for k in [a for a, e in self._per_agent.items() if e.last_used < cutoff]:
|
|
100
|
-
del self._per_agent[
|
|
100
|
+
del self._per_agent[k]
|
|
101
101
|
|
|
102
102
|
def _get_pid(self, pid: int, now: float) -> TokenBucket:
|
|
103
103
|
entry = self._per_pid.get(pid)
|
|
@@ -177,6 +177,34 @@ def _get_forgetting_scheduler(db: Any, config: Any) -> Any:
|
|
|
177
177
|
return _forgetting_scheduler_cache[key]
|
|
178
178
|
|
|
179
179
|
|
|
180
|
+
def release_recall_resources(db: Any) -> None:
|
|
181
|
+
"""Release process-level recall singletons owned by a closing database."""
|
|
182
|
+
key = id(db)
|
|
183
|
+
_behavioral_tracker_cache.pop(key, None)
|
|
184
|
+
_forgetting_scheduler_cache.pop(key, None)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _behavioral_entities(results: list[Any], limit: int = 20) -> list[str]:
|
|
188
|
+
"""Read canonical entity IDs from the typed retrieval-result contract.
|
|
189
|
+
|
|
190
|
+
``RetrievalResult`` is a dataclass whose entity evidence lives on
|
|
191
|
+
``result.fact.canonical_entities``. Treating it as a SQLite mapping silently
|
|
192
|
+
discarded every entity and disabled behavioral entity learning.
|
|
193
|
+
"""
|
|
194
|
+
entities: list[str] = []
|
|
195
|
+
seen: set[str] = set()
|
|
196
|
+
for result in results:
|
|
197
|
+
fact = getattr(result, "fact", None)
|
|
198
|
+
for entity_id in getattr(fact, "canonical_entities", ()) or ():
|
|
199
|
+
if not isinstance(entity_id, str) or not entity_id or entity_id in seen:
|
|
200
|
+
continue
|
|
201
|
+
seen.add(entity_id)
|
|
202
|
+
entities.append(entity_id)
|
|
203
|
+
if len(entities) >= limit:
|
|
204
|
+
return entities
|
|
205
|
+
return entities
|
|
206
|
+
|
|
207
|
+
|
|
180
208
|
# ---------------------------------------------------------------------------
|
|
181
209
|
# S8-ARC-04 (v3.4.22): unified ranking entry point.
|
|
182
210
|
# ---------------------------------------------------------------------------
|
|
@@ -268,10 +296,10 @@ def apply_adaptive_ranking(
|
|
|
268
296
|
Phase 2 (50+): heuristic boosts from recency, access count, trust.
|
|
269
297
|
Phase 3 (200+): LightGBM ML-based reranking.
|
|
270
298
|
"""
|
|
299
|
+
from superlocalmemory.infra.data_root import state_path
|
|
271
300
|
from superlocalmemory.learning.feedback import FeedbackCollector
|
|
272
|
-
from pathlib import Path
|
|
273
301
|
|
|
274
|
-
learning_db =
|
|
302
|
+
learning_db = state_path("learning.db")
|
|
275
303
|
if not learning_db.exists():
|
|
276
304
|
return response
|
|
277
305
|
|
|
@@ -284,7 +312,8 @@ def apply_adaptive_ranking(
|
|
|
284
312
|
from superlocalmemory.learning.ranker import AdaptiveRanker
|
|
285
313
|
ranker = AdaptiveRanker(signal_count=signal_count)
|
|
286
314
|
|
|
287
|
-
from datetime import UTC
|
|
315
|
+
from datetime import UTC
|
|
316
|
+
from datetime import datetime as _dt
|
|
288
317
|
_now = _dt.now(UTC)
|
|
289
318
|
|
|
290
319
|
result_dicts = []
|
|
@@ -314,6 +343,10 @@ def apply_adaptive_ranking(
|
|
|
314
343
|
reranked = ranker.rerank(result_dicts, query_context)
|
|
315
344
|
|
|
316
345
|
# Rebuild response with new ordering
|
|
346
|
+
for item in reranked:
|
|
347
|
+
original = item.get("_original")
|
|
348
|
+
if original is not None and item.get("_adaptive_score") is not None:
|
|
349
|
+
original.ranking_score = float(item["_adaptive_score"])
|
|
317
350
|
new_results = [d["_original"] for d in reranked]
|
|
318
351
|
|
|
319
352
|
return RecallResponse(
|
|
@@ -354,17 +387,13 @@ def apply_v2_adaptive_ranking(
|
|
|
354
387
|
try:
|
|
355
388
|
from pathlib import Path as _P
|
|
356
389
|
|
|
390
|
+
from superlocalmemory.infra.data_root import state_path
|
|
357
391
|
from superlocalmemory.learning.database import LearningDatabase
|
|
358
392
|
from superlocalmemory.learning.model_cache import load_active
|
|
359
393
|
from superlocalmemory.learning.ranker import AdaptiveRanker
|
|
360
|
-
from superlocalmemory.learning.signals import (
|
|
361
|
-
SignalBatch,
|
|
362
|
-
SignalCandidate,
|
|
363
|
-
enqueue,
|
|
364
|
-
)
|
|
365
394
|
|
|
366
395
|
db_path = (_P(learning_db_path) if learning_db_path
|
|
367
|
-
else
|
|
396
|
+
else state_path("learning.db"))
|
|
368
397
|
if not db_path.exists():
|
|
369
398
|
return response
|
|
370
399
|
|
|
@@ -378,7 +407,8 @@ def apply_v2_adaptive_ranking(
|
|
|
378
407
|
)
|
|
379
408
|
|
|
380
409
|
# Build result-dict shape expected by the ranker's rerank() path.
|
|
381
|
-
from datetime import UTC
|
|
410
|
+
from datetime import UTC
|
|
411
|
+
from datetime import datetime as _dt
|
|
382
412
|
_now_v2 = _dt.now(UTC)
|
|
383
413
|
|
|
384
414
|
result_dicts: list[dict] = []
|
|
@@ -410,6 +440,10 @@ def apply_v2_adaptive_ranking(
|
|
|
410
440
|
"profile_id": profile_id,
|
|
411
441
|
}
|
|
412
442
|
reranked_dicts = ranker.rerank(result_dicts, query_context)
|
|
443
|
+
for item in reranked_dicts:
|
|
444
|
+
original = item.get("_original")
|
|
445
|
+
if original is not None and item.get("_adaptive_score") is not None:
|
|
446
|
+
original.ranking_score = float(item["_adaptive_score"])
|
|
413
447
|
new_results = [d["_original"] for d in reranked_dicts
|
|
414
448
|
if "_original" in d]
|
|
415
449
|
|
|
@@ -463,9 +497,9 @@ def apply_v2_bandit_ensemble(
|
|
|
463
497
|
return response
|
|
464
498
|
|
|
465
499
|
try:
|
|
466
|
-
from datetime import datetime as _dt
|
|
467
500
|
from pathlib import Path as _P
|
|
468
501
|
|
|
502
|
+
from superlocalmemory.infra.data_root import state_path
|
|
469
503
|
from superlocalmemory.learning.bandit import ContextualBandit
|
|
470
504
|
from superlocalmemory.learning.ensemble import (
|
|
471
505
|
choose_ensemble,
|
|
@@ -479,7 +513,7 @@ def apply_v2_bandit_ensemble(
|
|
|
479
513
|
from superlocalmemory.retrieval.engine import apply_channel_weights
|
|
480
514
|
|
|
481
515
|
db_path = (_P(learning_db_path) if learning_db_path
|
|
482
|
-
else
|
|
516
|
+
else state_path("learning.db"))
|
|
483
517
|
if not db_path.exists():
|
|
484
518
|
return response
|
|
485
519
|
|
|
@@ -597,9 +631,8 @@ def run_recall(
|
|
|
597
631
|
|
|
598
632
|
Pipeline: retrieval -> agentic sufficiency (if configured) -> post-recall updates.
|
|
599
633
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
response.
|
|
634
|
+
``fast=True`` skips spreading activation and remote agentic verification,
|
|
635
|
+
retaining the bounded single-pass retrieval channels.
|
|
603
636
|
"""
|
|
604
637
|
# Pre-operation hooks
|
|
605
638
|
hook_ctx = {
|
|
@@ -639,7 +672,7 @@ def run_recall(
|
|
|
639
672
|
# Single-hop/factual/temporal queries get WORSE with decomposition —
|
|
640
673
|
# sub-query noise dilutes precision. Mode C (LLM) can trigger broadly.
|
|
641
674
|
agentic_rounds = config.retrieval.agentic_max_rounds
|
|
642
|
-
if agentic_rounds > 0 and response.results:
|
|
675
|
+
if not fast and agentic_rounds > 0 and response.results:
|
|
643
676
|
max_score = max((r.score for r in response.results), default=0.0)
|
|
644
677
|
has_llm = llm is not None and getattr(llm, "is_available", False)
|
|
645
678
|
should_trigger = (
|
|
@@ -679,6 +712,9 @@ def run_recall(
|
|
|
679
712
|
fact=f, score=1.0 / (i + 1),
|
|
680
713
|
channel_scores={"agentic": 1.0},
|
|
681
714
|
confidence=f.confidence,
|
|
715
|
+
relevance_score=1.0 / (i + 1),
|
|
716
|
+
ranking_score=None,
|
|
717
|
+
memory_confidence=f.confidence,
|
|
682
718
|
evidence_chain=["agentic_round_2"],
|
|
683
719
|
trust_score=fact_trust,
|
|
684
720
|
))
|
|
@@ -708,58 +744,18 @@ def run_recall(
|
|
|
708
744
|
except Exception as exc:
|
|
709
745
|
logger.debug("Access log batch store failed: %s", exc)
|
|
710
746
|
|
|
711
|
-
#
|
|
712
|
-
|
|
713
|
-
try:
|
|
714
|
-
from superlocalmemory.core.tier_manager import promote_on_access_batch
|
|
715
|
-
fact_ids = [r.fact.fact_id for r in response.results[:10]]
|
|
716
|
-
promote_on_access_batch(db, fact_ids)
|
|
717
|
-
except Exception:
|
|
718
|
-
pass # tier_manager not available yet — graceful
|
|
719
|
-
|
|
720
|
-
# V3.3.16: Behavioral tracking + spaced repetition use module-level
|
|
721
|
-
# singletons to avoid creating new objects per recall (was causing
|
|
722
|
-
# object accumulation across 304 benchmark recalls).
|
|
747
|
+
# Query telemetry is permitted, but result-derived entities are not fed
|
|
748
|
+
# back as preferences. Retrieval exposure is not positive feedback.
|
|
723
749
|
try:
|
|
724
|
-
# v3.4.7: Extract entities from results for behavioral tracking.
|
|
725
|
-
# Was passing wrong param (result_count instead of entities) → TypeError.
|
|
726
|
-
entities: list[str] = []
|
|
727
|
-
for r in response.results[:10]:
|
|
728
|
-
rd = r if isinstance(r, dict) else (dict(r) if hasattr(r, "keys") else {})
|
|
729
|
-
ents_json = rd.get("canonical_entities_json", "")
|
|
730
|
-
if ents_json:
|
|
731
|
-
try:
|
|
732
|
-
import json as _json
|
|
733
|
-
entities.extend(_json.loads(ents_json))
|
|
734
|
-
except (ValueError, TypeError):
|
|
735
|
-
pass
|
|
736
750
|
_get_behavioral_tracker(db).record_query(
|
|
737
751
|
query=query,
|
|
738
752
|
query_type=response.query_type,
|
|
739
|
-
entities=
|
|
753
|
+
entities=[],
|
|
740
754
|
profile_id=profile_id,
|
|
741
755
|
)
|
|
742
756
|
except Exception as exc:
|
|
743
757
|
logger.debug("Behavioral tracking: %s", exc)
|
|
744
758
|
|
|
745
|
-
if response.results:
|
|
746
|
-
try:
|
|
747
|
-
fsched = _get_forgetting_scheduler(db, config)
|
|
748
|
-
for r in response.results[:10]:
|
|
749
|
-
fsched.on_access_event(r.fact.fact_id, profile_id)
|
|
750
|
-
except Exception as exc:
|
|
751
|
-
logger.debug("Spaced repetition update: %s", exc)
|
|
752
|
-
|
|
753
|
-
# Phase 3: Hebbian strengthening for co-accessed facts
|
|
754
|
-
if auto_linker and response.results:
|
|
755
|
-
try:
|
|
756
|
-
recalled_ids = [
|
|
757
|
-
r.fact.fact_id for r in response.results[:10]
|
|
758
|
-
]
|
|
759
|
-
auto_linker.strengthen_co_access(recalled_ids, profile_id)
|
|
760
|
-
except Exception as exc:
|
|
761
|
-
logger.debug("Hebbian strengthening: %s", exc)
|
|
762
|
-
|
|
763
759
|
# S8-ARC-04 (v3.4.22): unified ranking entry point. Single env-var
|
|
764
760
|
# (SLM_RANKING=off|v1|v2|v2-ensemble) controls the pipeline. Legacy
|
|
765
761
|
# SLM_V2_PIPELINE_DISABLED + SLM_BANDIT_DISABLED still honoured for
|
|
@@ -777,54 +773,17 @@ def run_recall(
|
|
|
777
773
|
logger.debug("Ranking pipeline skipped: %s", exc)
|
|
778
774
|
|
|
779
775
|
_mark("learning+ranking")
|
|
780
|
-
#
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
trust_scorer.update_on_access("fact", r.fact.fact_id, profile_id)
|
|
784
|
-
|
|
785
|
-
# Fisher Bayesian update on recall — narrows variance on accessed facts
|
|
786
|
-
# so they score higher on subsequent recalls (critical for benchmark: +24pp).
|
|
787
|
-
# V3.3.16: Reuse query embedding from retrieval engine cache instead of
|
|
788
|
-
# calling embedder.embed() again (which was the memory leak source).
|
|
789
|
-
q_var_arr = None
|
|
790
|
-
if embedder and hasattr(retrieval_engine, '_query_embedding_cache'):
|
|
791
|
-
cached_emb = retrieval_engine._query_embedding_cache.get(query)
|
|
792
|
-
if cached_emb is not None:
|
|
793
|
-
import numpy as _np
|
|
794
|
-
_, q_var_list = embedder.compute_fisher_params(cached_emb)
|
|
795
|
-
q_var_arr = _np.array(q_var_list, dtype=_np.float64)
|
|
796
|
-
|
|
797
|
-
for r in response.results:
|
|
798
|
-
updates: dict[str, object] = {
|
|
799
|
-
"access_count": r.fact.access_count + 1,
|
|
800
|
-
}
|
|
801
|
-
if (q_var_arr is not None
|
|
802
|
-
and r.fact.fisher_variance
|
|
803
|
-
and len(r.fact.fisher_variance) == len(q_var_arr)
|
|
804
|
-
and r.fact.access_count >= 3):
|
|
805
|
-
import numpy as _np
|
|
806
|
-
f_var = _np.array(r.fact.fisher_variance, dtype=_np.float64)
|
|
807
|
-
new_var = 1.0 / (1.0 / _np.maximum(f_var, 0.05) + 1.0 / _np.maximum(q_var_arr, 0.05))
|
|
808
|
-
new_var = _np.clip(new_var, 0.05, 2.0)
|
|
809
|
-
updates["fisher_variance"] = new_var.tolist()
|
|
810
|
-
db.update_fact(r.fact.fact_id, updates)
|
|
776
|
+
# Deliberately no trust, Fisher, retention, lifecycle, popularity, or graph
|
|
777
|
+
# mutation here. Those state transitions require a separately authenticated
|
|
778
|
+
# positive/negative outcome; merely returning a result is an exposure.
|
|
811
779
|
|
|
812
780
|
# Post-operation hooks (audit, trust signal, learning)
|
|
813
781
|
hook_ctx["result_count"] = len(response.results)
|
|
814
782
|
hook_ctx["query_type"] = response.query_type
|
|
815
783
|
hooks.run_post("recall", hook_ctx)
|
|
816
784
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
# (v1/v2/bandit-ensemble) re-weights and may produce scores outside [0,1].
|
|
820
|
-
# This final sigmoid catches every path (MCP/CLI/Dashboard) and is monotonic.
|
|
821
|
-
if response.results:
|
|
822
|
-
import math as _mn
|
|
823
|
-
max_s = max((r.score for r in response.results), default=1.0)
|
|
824
|
-
scale = 2.0 / max(1.0, max_s)
|
|
825
|
-
for r in response.results:
|
|
826
|
-
r.score = round(1.0 / (1.0 + _mn.exp(-r.score * scale)), 4)
|
|
827
|
-
r.confidence = min(1.0, r.score * 2.0)
|
|
785
|
+
from superlocalmemory.core.score_contract import finalize_score_contract
|
|
786
|
+
finalize_score_contract(response)
|
|
828
787
|
|
|
829
788
|
# LLD-00 §3 — stamp HMAC markers on every result so post_tool_outcome_hook
|
|
830
789
|
# can validate fact_ids observed in downstream tool output.
|
|
@@ -78,7 +78,10 @@ def _handle_recall(
|
|
|
78
78
|
|
|
79
79
|
# v3.6.6: same shared chokepoint as the daemon HTTP route + CLI fallback,
|
|
80
80
|
# so the MCP WorkerPool subprocess path returns identical budgeted output.
|
|
81
|
-
from superlocalmemory.server.recall_serializer import
|
|
81
|
+
from superlocalmemory.server.recall_serializer import (
|
|
82
|
+
recall_response_metadata,
|
|
83
|
+
serialize_recall_response,
|
|
84
|
+
)
|
|
82
85
|
_rc = getattr(engine._config, "retrieval", None)
|
|
83
86
|
results, no_confident_match = serialize_recall_response(
|
|
84
87
|
response,
|
|
@@ -99,13 +102,43 @@ def _handle_recall(
|
|
|
99
102
|
"total_candidates": getattr(response, "total_candidates", 0),
|
|
100
103
|
"results": results,
|
|
101
104
|
"no_confident_match": no_confident_match,
|
|
105
|
+
**recall_response_metadata(response),
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
|
|
105
109
|
def _handle_store(content: str, metadata: dict) -> dict:
|
|
106
110
|
engine = _get_engine()
|
|
107
|
-
|
|
108
|
-
|
|
111
|
+
values = dict(metadata or {})
|
|
112
|
+
session_id = str(values.pop("session_id", "") or "")
|
|
113
|
+
scope = str(values.pop("scope", "personal") or "personal")
|
|
114
|
+
shared_with = list(values.pop("shared_with", []) or [])
|
|
115
|
+
idempotency_key = str(values.pop("idempotency_key", "") or "")
|
|
116
|
+
from superlocalmemory.core.engine_ingestion import (
|
|
117
|
+
canonical_store,
|
|
118
|
+
local_trusted_actor_id,
|
|
119
|
+
)
|
|
120
|
+
operation = canonical_store(
|
|
121
|
+
engine,
|
|
122
|
+
content,
|
|
123
|
+
source_type="mcp-offline-worker",
|
|
124
|
+
trusted_actor_id=local_trusted_actor_id("recall-worker"),
|
|
125
|
+
metadata=values,
|
|
126
|
+
scope=scope,
|
|
127
|
+
shared_with=shared_with,
|
|
128
|
+
session_id=session_id,
|
|
129
|
+
idempotency_key=idempotency_key,
|
|
130
|
+
return_receipt=True,
|
|
131
|
+
)
|
|
132
|
+
if hasattr(operation, "fact_ids"):
|
|
133
|
+
fact_ids = list(operation.fact_ids)
|
|
134
|
+
operation_id = getattr(operation, "operation_id", None)
|
|
135
|
+
materialization_state = getattr(
|
|
136
|
+
getattr(operation, "state", None), "value", "complete"
|
|
137
|
+
)
|
|
138
|
+
else:
|
|
139
|
+
fact_ids = list(operation)
|
|
140
|
+
operation_id = None
|
|
141
|
+
materialization_state = "complete"
|
|
109
142
|
|
|
110
143
|
# Generate and persist summary immediately after store (Mode A heuristic, B/C LLM)
|
|
111
144
|
if fact_ids:
|
|
@@ -125,7 +158,15 @@ def _handle_store(content: str, metadata: dict) -> dict:
|
|
|
125
158
|
except Exception:
|
|
126
159
|
pass # Summary is non-critical
|
|
127
160
|
|
|
128
|
-
|
|
161
|
+
pending = materialization_state != "complete"
|
|
162
|
+
return {
|
|
163
|
+
"ok": True,
|
|
164
|
+
"fact_ids": fact_ids,
|
|
165
|
+
"count": len(fact_ids),
|
|
166
|
+
"operation_id": operation_id,
|
|
167
|
+
"pending_id": operation_id if pending else None,
|
|
168
|
+
"materialization_state": materialization_state,
|
|
169
|
+
}
|
|
129
170
|
|
|
130
171
|
|
|
131
172
|
def _handle_get_memory_facts(memory_id: str) -> dict:
|
|
@@ -154,65 +195,40 @@ def _handle_get_memory_facts(memory_id: str) -> dict:
|
|
|
154
195
|
}
|
|
155
196
|
|
|
156
197
|
|
|
157
|
-
def _handle_delete_memory(
|
|
158
|
-
|
|
198
|
+
def _handle_delete_memory(
|
|
199
|
+
fact_id: str,
|
|
200
|
+
source_agent_id: str = "system",
|
|
201
|
+
) -> dict:
|
|
202
|
+
"""Delete a fact after capability-derived authorization."""
|
|
159
203
|
engine = _get_engine()
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
204
|
+
from superlocalmemory.core.engine_ingestion import local_trusted_actor_id
|
|
205
|
+
from superlocalmemory.core.mutations import delete_fact_authorized
|
|
206
|
+
|
|
207
|
+
return delete_fact_authorized(
|
|
208
|
+
engine,
|
|
209
|
+
fact_id,
|
|
210
|
+
trusted_actor_id=local_trusted_actor_id("recall-worker"),
|
|
211
|
+
source_agent_id=source_agent_id,
|
|
164
212
|
)
|
|
165
|
-
if not rows:
|
|
166
|
-
return {"ok": False, "error": f"Memory {fact_id} not found"}
|
|
167
|
-
content_preview = dict(rows[0]).get("content", "")[:80]
|
|
168
|
-
engine._db.delete_fact(fact_id)
|
|
169
|
-
# Audit log
|
|
170
|
-
import logging as _logging
|
|
171
|
-
_logging.getLogger("superlocalmemory.audit").info(
|
|
172
|
-
"DELETE fact_id=%s by agent=%s content=%s", fact_id[:16], agent_id, content_preview,
|
|
173
|
-
)
|
|
174
|
-
return {"ok": True, "deleted": fact_id, "content_preview": content_preview}
|
|
175
213
|
|
|
176
214
|
|
|
177
|
-
def _handle_update_memory(
|
|
178
|
-
|
|
215
|
+
def _handle_update_memory(
|
|
216
|
+
fact_id: str,
|
|
217
|
+
content: str,
|
|
218
|
+
source_agent_id: str = "system",
|
|
219
|
+
) -> dict:
|
|
220
|
+
"""Update a fact after capability-derived authorization."""
|
|
179
221
|
engine = _get_engine()
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
# Previously only the text column was updated, leaving stale embeddings.
|
|
190
|
-
updates: dict = {"content": content}
|
|
191
|
-
if engine._embedder:
|
|
192
|
-
try:
|
|
193
|
-
new_emb = engine._embedder.embed(content)
|
|
194
|
-
if new_emb:
|
|
195
|
-
updates["embedding"] = new_emb
|
|
196
|
-
fm, fv = engine._embedder.compute_fisher_params(new_emb)
|
|
197
|
-
updates["fisher_mean"] = fm
|
|
198
|
-
updates["fisher_variance"] = fv
|
|
199
|
-
except Exception:
|
|
200
|
-
pass
|
|
201
|
-
engine._db.update_fact(fact_id, updates)
|
|
202
|
-
# Update BM25 index for the new content
|
|
203
|
-
if hasattr(engine, '_retrieval_engine') and engine._retrieval_engine:
|
|
204
|
-
bm25 = getattr(engine._retrieval_engine, '_bm25', None)
|
|
205
|
-
if bm25:
|
|
206
|
-
try:
|
|
207
|
-
bm25.add(fact_id, content, pid)
|
|
208
|
-
except Exception:
|
|
209
|
-
pass
|
|
210
|
-
import logging as _logging
|
|
211
|
-
_logging.getLogger("superlocalmemory.audit").info(
|
|
212
|
-
"UPDATE fact_id=%s by agent=%s old=%s new=%s",
|
|
213
|
-
fact_id[:16], agent_id, old_content, content[:80],
|
|
222
|
+
from superlocalmemory.core.engine_ingestion import local_trusted_actor_id
|
|
223
|
+
from superlocalmemory.core.mutations import update_fact_authorized
|
|
224
|
+
|
|
225
|
+
return update_fact_authorized(
|
|
226
|
+
engine,
|
|
227
|
+
fact_id,
|
|
228
|
+
content,
|
|
229
|
+
trusted_actor_id=local_trusted_actor_id("recall-worker"),
|
|
230
|
+
source_agent_id=source_agent_id,
|
|
214
231
|
)
|
|
215
|
-
return {"ok": True, "fact_id": fact_id, "content": content}
|
|
216
232
|
|
|
217
233
|
|
|
218
234
|
def _handle_summarize(texts: list[str], mode: str) -> dict:
|
|
@@ -299,14 +315,15 @@ def _worker_main() -> None:
|
|
|
299
315
|
_respond(result)
|
|
300
316
|
elif cmd == "delete_memory":
|
|
301
317
|
result = _handle_delete_memory(
|
|
302
|
-
req.get("fact_id", ""),
|
|
318
|
+
req.get("fact_id", ""),
|
|
319
|
+
req.get("source_agent_id", req.get("agent_id", "system")),
|
|
303
320
|
)
|
|
304
321
|
_respond(result)
|
|
305
322
|
elif cmd == "update_memory":
|
|
306
323
|
result = _handle_update_memory(
|
|
307
324
|
req.get("fact_id", ""),
|
|
308
325
|
req.get("content", ""),
|
|
309
|
-
req.get("agent_id", "system"),
|
|
326
|
+
req.get("source_agent_id", req.get("agent_id", "system")),
|
|
310
327
|
)
|
|
311
328
|
_respond(result)
|
|
312
329
|
elif cmd == "get_memory_facts":
|