superlocalmemory 4.1.13 → 4.1.14
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/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +48 -0
- package/README.md +3 -3
- package/package.json +1 -8
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/CLAUDE.md +3 -3
- package/plugin/agents/slm-governance-advisor.md +1 -1
- package/plugin/agents/slm-loop-runner.md +1 -1
- package/plugin/agents/slm-memory-advisor.md +1 -1
- package/plugin/agents/slm-optimize-advisor.md +1 -1
- package/plugin/requirements.txt +1 -1
- package/plugin/skills/slm-cache/SKILL.md +1 -1
- package/plugin/skills/slm-compress/SKILL.md +1 -1
- package/plugin/skills/slm-governance/SKILL.md +1 -1
- package/plugin/skills/slm-graph/SKILL.md +1 -1
- package/plugin/skills/slm-loop/SKILL.md +1 -1
- package/plugin/skills/slm-mesh/SKILL.md +1 -1
- package/plugin/skills/slm-profile/SKILL.md +1 -1
- package/plugin/skills/slm-recall/SKILL.md +1 -1
- package/plugin/skills/slm-remember/SKILL.md +1 -1
- package/plugin/skills/slm-scope/SKILL.md +1 -1
- package/plugin/skills/slm-session/SKILL.md +1 -1
- package/plugin/skills/slm-status/SKILL.md +1 -1
- package/plugin-src/agents/slm-memory-advisor.md +1 -1
- package/plugin-src/agents/slm-optimize-advisor.md +1 -1
- package/plugin-src/rules/AGENTS.md +1 -1
- package/plugin-src/skills/slm-cache/SKILL.md +1 -1
- package/plugin-src/skills/slm-compress/SKILL.md +1 -1
- package/plugin-src/skills/slm-governance/SKILL.md +1 -1
- package/plugin-src/skills/slm-graph/SKILL.md +1 -1
- package/plugin-src/skills/slm-loop/SKILL.md +1 -1
- package/plugin-src/skills/slm-mesh/SKILL.md +1 -1
- package/plugin-src/skills/slm-profile/SKILL.md +1 -1
- package/plugin-src/skills/slm-recall/SKILL.md +1 -1
- package/plugin-src/skills/slm-remember/SKILL.md +1 -1
- package/plugin-src/skills/slm-scope/SKILL.md +1 -1
- package/plugin-src/skills/slm-session/SKILL.md +1 -1
- package/plugin-src/skills/slm-status/SKILL.md +1 -1
- package/scripts/postinstall.js +71 -2
- package/pyproject.toml +0 -250
- package/src/superlocalmemory/__init__.py +0 -82
- package/src/superlocalmemory/access/__init__.py +0 -3
- package/src/superlocalmemory/access/rbac.py +0 -575
- package/src/superlocalmemory/attribution/__init__.py +0 -9
- package/src/superlocalmemory/attribution/signer.py +0 -173
- package/src/superlocalmemory/attribution/watermark.py +0 -189
- package/src/superlocalmemory/brain/__init__.py +0 -5
- package/src/superlocalmemory/brain/truth.py +0 -418
- package/src/superlocalmemory/cli/__init__.py +0 -5
- package/src/superlocalmemory/cli/__main__.py +0 -17
- package/src/superlocalmemory/cli/_lazy_init.py +0 -115
- package/src/superlocalmemory/cli/cache_cmd.py +0 -198
- package/src/superlocalmemory/cli/commands.py +0 -4710
- package/src/superlocalmemory/cli/compress_cmd.py +0 -151
- package/src/superlocalmemory/cli/context_commands.py +0 -193
- package/src/superlocalmemory/cli/daemon.py +0 -909
- package/src/superlocalmemory/cli/db_migrate.py +0 -150
- package/src/superlocalmemory/cli/diagnostics_cmd.py +0 -101
- package/src/superlocalmemory/cli/escape_hatch.py +0 -220
- package/src/superlocalmemory/cli/evidence_cmd.py +0 -103
- package/src/superlocalmemory/cli/gdpr_cmd.py +0 -792
- package/src/superlocalmemory/cli/gdpr_io.py +0 -109
- package/src/superlocalmemory/cli/help_cmd.py +0 -197
- package/src/superlocalmemory/cli/host_upgrades.py +0 -189
- package/src/superlocalmemory/cli/ingest_cmd.py +0 -327
- package/src/superlocalmemory/cli/json_output.py +0 -81
- package/src/superlocalmemory/cli/loop_cmd.py +0 -187
- package/src/superlocalmemory/cli/main.py +0 -1145
- package/src/superlocalmemory/cli/mesh_cmd.py +0 -38
- package/src/superlocalmemory/cli/migrate_cmd.py +0 -55
- package/src/superlocalmemory/cli/ops_cmd.py +0 -281
- package/src/superlocalmemory/cli/optimize_cmd.py +0 -179
- package/src/superlocalmemory/cli/optimize_constants.py +0 -31
- package/src/superlocalmemory/cli/pending_store.py +0 -296
- package/src/superlocalmemory/cli/proxy_cmd.py +0 -108
- package/src/superlocalmemory/cli/scale_engine_cmd.py +0 -56
- package/src/superlocalmemory/cli/service_installer.py +0 -373
- package/src/superlocalmemory/cli/setup_wizard.py +0 -1162
- package/src/superlocalmemory/cli/summary_cmd.py +0 -215
- package/src/superlocalmemory/cli/version_banner.py +0 -202
- package/src/superlocalmemory/cli/wizard_v3426_options.py +0 -129
- package/src/superlocalmemory/code_graph/__init__.py +0 -46
- package/src/superlocalmemory/code_graph/blast_radius.py +0 -177
- package/src/superlocalmemory/code_graph/bridge/__init__.py +0 -36
- package/src/superlocalmemory/code_graph/bridge/entity_resolver.py +0 -490
- package/src/superlocalmemory/code_graph/bridge/event_listeners.py +0 -206
- package/src/superlocalmemory/code_graph/bridge/fact_enricher.py +0 -159
- package/src/superlocalmemory/code_graph/bridge/hebbian_linker.py +0 -170
- package/src/superlocalmemory/code_graph/bridge/maintenance.py +0 -220
- package/src/superlocalmemory/code_graph/bridge/temporal_checker.py +0 -152
- package/src/superlocalmemory/code_graph/changes.py +0 -363
- package/src/superlocalmemory/code_graph/communities.py +0 -299
- package/src/superlocalmemory/code_graph/config.py +0 -154
- package/src/superlocalmemory/code_graph/database.py +0 -526
- package/src/superlocalmemory/code_graph/extractors/__init__.py +0 -95
- package/src/superlocalmemory/code_graph/extractors/python.py +0 -413
- package/src/superlocalmemory/code_graph/extractors/typescript.py +0 -556
- package/src/superlocalmemory/code_graph/flows.py +0 -350
- package/src/superlocalmemory/code_graph/git_hooks.py +0 -226
- package/src/superlocalmemory/code_graph/graph_engine.py +0 -295
- package/src/superlocalmemory/code_graph/graph_store.py +0 -335
- package/src/superlocalmemory/code_graph/incremental.py +0 -200
- package/src/superlocalmemory/code_graph/models.py +0 -130
- package/src/superlocalmemory/code_graph/parser.py +0 -687
- package/src/superlocalmemory/code_graph/resolver.py +0 -321
- package/src/superlocalmemory/code_graph/search.py +0 -460
- package/src/superlocalmemory/code_graph/service.py +0 -95
- package/src/superlocalmemory/code_graph/watcher.py +0 -207
- package/src/superlocalmemory/compliance/__init__.py +0 -0
- package/src/superlocalmemory/compliance/abac.py +0 -204
- package/src/superlocalmemory/compliance/audit.py +0 -385
- package/src/superlocalmemory/compliance/eu_ai_act.py +0 -101
- package/src/superlocalmemory/compliance/gdpr.py +0 -1479
- package/src/superlocalmemory/compliance/lifecycle.py +0 -158
- package/src/superlocalmemory/compliance/retention.py +0 -415
- package/src/superlocalmemory/compliance/scheduler.py +0 -217
- package/src/superlocalmemory/contracts/__init__.py +0 -1
- package/src/superlocalmemory/contracts/schemas/agent-experience-v1.schema.json +0 -92
- package/src/superlocalmemory/contracts/schemas/agent-integration-contract-v2.schema.json +0 -46
- package/src/superlocalmemory/contracts/schemas/cognitive-turn-receipt-v1.schema.json +0 -59
- package/src/superlocalmemory/contracts/v402.py +0 -62
- package/src/superlocalmemory/core/__init__.py +0 -0
- package/src/superlocalmemory/core/actor_context.py +0 -166
- package/src/superlocalmemory/core/admission.py +0 -769
- package/src/superlocalmemory/core/backend_orchestrator.py +0 -637
- package/src/superlocalmemory/core/block_hygiene.py +0 -147
- package/src/superlocalmemory/core/community_summary.py +0 -267
- package/src/superlocalmemory/core/component_healer.py +0 -144
- package/src/superlocalmemory/core/component_registry.py +0 -514
- package/src/superlocalmemory/core/config.py +0 -2204
- package/src/superlocalmemory/core/consolidation_engine.py +0 -983
- package/src/superlocalmemory/core/context_cache.py +0 -574
- package/src/superlocalmemory/core/derivation_lineage.py +0 -246
- package/src/superlocalmemory/core/embedding_worker.py +0 -208
- package/src/superlocalmemory/core/embeddings.py +0 -1052
- package/src/superlocalmemory/core/engine.py +0 -1395
- package/src/superlocalmemory/core/engine_capabilities.py +0 -24
- package/src/superlocalmemory/core/engine_ingestion.py +0 -983
- package/src/superlocalmemory/core/engine_lock.py +0 -75
- package/src/superlocalmemory/core/engine_wiring.py +0 -776
- package/src/superlocalmemory/core/entity_community.py +0 -178
- package/src/superlocalmemory/core/error_envelope.py +0 -60
- package/src/superlocalmemory/core/evidence_bundle.py +0 -528
- package/src/superlocalmemory/core/fact_consolidator.py +0 -812
- package/src/superlocalmemory/core/file_lock.py +0 -92
- package/src/superlocalmemory/core/graph_analyzer.py +0 -456
- package/src/superlocalmemory/core/graph_metrics.py +0 -597
- package/src/superlocalmemory/core/graph_pruner.py +0 -939
- package/src/superlocalmemory/core/health_monitor.py +0 -338
- package/src/superlocalmemory/core/hooks.py +0 -65
- package/src/superlocalmemory/core/ingest_gate.py +0 -133
- package/src/superlocalmemory/core/ingest_policy.py +0 -38
- package/src/superlocalmemory/core/ingestion_command.py +0 -1042
- package/src/superlocalmemory/core/injection.py +0 -434
- package/src/superlocalmemory/core/install_detector.py +0 -131
- package/src/superlocalmemory/core/key_expander.py +0 -138
- package/src/superlocalmemory/core/lifecycle_state.py +0 -153
- package/src/superlocalmemory/core/maintenance.py +0 -777
- package/src/superlocalmemory/core/maintenance_scheduler.py +0 -507
- package/src/superlocalmemory/core/materialization_control.py +0 -20
- package/src/superlocalmemory/core/mcp_embedder_proxy.py +0 -89
- package/src/superlocalmemory/core/memory_health.py +0 -266
- package/src/superlocalmemory/core/mode_capability.py +0 -111
- package/src/superlocalmemory/core/modes.py +0 -168
- package/src/superlocalmemory/core/mutations.py +0 -688
- package/src/superlocalmemory/core/ollama_embedder.py +0 -266
- package/src/superlocalmemory/core/ollama_validator.py +0 -315
- package/src/superlocalmemory/core/operation_policy.py +0 -92
- package/src/superlocalmemory/core/operation_policy_registry.py +0 -542
- package/src/superlocalmemory/core/operation_request.py +0 -127
- package/src/superlocalmemory/core/ops_remediation.py +0 -542
- package/src/superlocalmemory/core/pii.py +0 -105
- package/src/superlocalmemory/core/platform_utils.py +0 -138
- package/src/superlocalmemory/core/profiles.py +0 -234
- package/src/superlocalmemory/core/progressive_abstraction.py +0 -208
- package/src/superlocalmemory/core/projection_drain.py +0 -380
- package/src/superlocalmemory/core/queue_consumer.py +0 -168
- package/src/superlocalmemory/core/ram_lock.py +0 -160
- package/src/superlocalmemory/core/rate_limit.py +0 -151
- package/src/superlocalmemory/core/recall_gate.py +0 -95
- package/src/superlocalmemory/core/recall_pipeline.py +0 -1337
- package/src/superlocalmemory/core/recall_queue.py +0 -377
- package/src/superlocalmemory/core/recall_worker.py +0 -414
- package/src/superlocalmemory/core/registry.py +0 -121
- package/src/superlocalmemory/core/remember_admission.py +0 -161
- package/src/superlocalmemory/core/remember_runtime.py +0 -1190
- package/src/superlocalmemory/core/remote_mode.py +0 -214
- package/src/superlocalmemory/core/reranker_worker.py +0 -338
- package/src/superlocalmemory/core/safe_fs.py +0 -108
- package/src/superlocalmemory/core/scale_autopromote.py +0 -196
- package/src/superlocalmemory/core/scale_engine.py +0 -915
- package/src/superlocalmemory/core/score_contract.py +0 -82
- package/src/superlocalmemory/core/security_primitives.py +0 -672
- package/src/superlocalmemory/core/session_identity.py +0 -98
- package/src/superlocalmemory/core/shadow_router.py +0 -319
- package/src/superlocalmemory/core/slm_disabled.py +0 -85
- package/src/superlocalmemory/core/status_contract.py +0 -108
- package/src/superlocalmemory/core/store_pipeline.py +0 -1404
- package/src/superlocalmemory/core/summarizer.py +0 -200
- package/src/superlocalmemory/core/tier_manager.py +0 -461
- package/src/superlocalmemory/core/topic_signature.py +0 -156
- package/src/superlocalmemory/core/transactions/__init__.py +0 -78
- package/src/superlocalmemory/core/transactions/concrete_owners.py +0 -604
- package/src/superlocalmemory/core/transactions/erasure.py +0 -825
- package/src/superlocalmemory/core/transactions/manifest.py +0 -255
- package/src/superlocalmemory/core/transactions/manifest_key.py +0 -155
- package/src/superlocalmemory/core/transactions/obligations.py +0 -272
- package/src/superlocalmemory/core/transactions/owners.py +0 -114
- package/src/superlocalmemory/core/transactions/reconciler.py +0 -285
- package/src/superlocalmemory/core/transactions/service.py +0 -330
- package/src/superlocalmemory/core/worker_pool.py +0 -377
- package/src/superlocalmemory/core/working_memory.py +0 -288
- package/src/superlocalmemory/dynamics/__init__.py +0 -0
- package/src/superlocalmemory/dynamics/activation_guided_quantization.py +0 -374
- package/src/superlocalmemory/dynamics/eap_scheduler.py +0 -294
- package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +0 -171
- package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +0 -227
- package/src/superlocalmemory/encoding/__init__.py +0 -0
- package/src/superlocalmemory/encoding/auto_linker.py +0 -308
- package/src/superlocalmemory/encoding/cognitive_consolidator.py +0 -899
- package/src/superlocalmemory/encoding/consolidator.py +0 -472
- package/src/superlocalmemory/encoding/context_generator.py +0 -175
- package/src/superlocalmemory/encoding/emotional.py +0 -189
- package/src/superlocalmemory/encoding/entity_reflexion.py +0 -200
- package/src/superlocalmemory/encoding/entity_resolver.py +0 -687
- package/src/superlocalmemory/encoding/entropy_gate.py +0 -101
- package/src/superlocalmemory/encoding/fact_extractor.py +0 -877
- package/src/superlocalmemory/encoding/foresight.py +0 -93
- package/src/superlocalmemory/encoding/graph_builder.py +0 -346
- package/src/superlocalmemory/encoding/observation_builder.py +0 -177
- package/src/superlocalmemory/encoding/prospective_markers.py +0 -262
- package/src/superlocalmemory/encoding/scene_builder.py +0 -410
- package/src/superlocalmemory/encoding/signal_inference.py +0 -90
- package/src/superlocalmemory/encoding/temporal_parser.py +0 -432
- package/src/superlocalmemory/encoding/temporal_validator.py +0 -572
- package/src/superlocalmemory/encoding/type_router.py +0 -237
- package/src/superlocalmemory/evaluation/__init__.py +0 -13
- package/src/superlocalmemory/evaluation/calibration.py +0 -308
- package/src/superlocalmemory/evolution/__init__.py +0 -29
- package/src/superlocalmemory/evolution/blind_verifier.py +0 -122
- package/src/superlocalmemory/evolution/budget.py +0 -356
- package/src/superlocalmemory/evolution/evolution_store.py +0 -619
- package/src/superlocalmemory/evolution/llm_dispatch.py +0 -559
- package/src/superlocalmemory/evolution/model_selection.py +0 -175
- package/src/superlocalmemory/evolution/mutation_generator.py +0 -226
- package/src/superlocalmemory/evolution/skill_activator.py +0 -270
- package/src/superlocalmemory/evolution/skill_evolver.py +0 -928
- package/src/superlocalmemory/evolution/triggers.py +0 -376
- package/src/superlocalmemory/evolution/types.py +0 -114
- package/src/superlocalmemory/graph/__init__.py +0 -9
- package/src/superlocalmemory/graph/cozo_adjacency.py +0 -122
- package/src/superlocalmemory/graph/cozo_backend.py +0 -751
- package/src/superlocalmemory/hooks/__init__.py +0 -3
- package/src/superlocalmemory/hooks/_outcome_common.py +0 -523
- package/src/superlocalmemory/hooks/adapter_base.py +0 -347
- package/src/superlocalmemory/hooks/antigravity_adapter.py +0 -171
- package/src/superlocalmemory/hooks/auto_capture.py +0 -133
- package/src/superlocalmemory/hooks/auto_invoker.py +0 -521
- package/src/superlocalmemory/hooks/auto_parameterize.py +0 -147
- package/src/superlocalmemory/hooks/auto_recall.py +0 -191
- package/src/superlocalmemory/hooks/auto_recall_hook.py +0 -251
- package/src/superlocalmemory/hooks/before_web_hook.py +0 -131
- package/src/superlocalmemory/hooks/claude_code_hooks.py +0 -637
- package/src/superlocalmemory/hooks/codex_assets.py +0 -251
- package/src/superlocalmemory/hooks/codex_hooks.py +0 -186
- package/src/superlocalmemory/hooks/context_payload.py +0 -311
- package/src/superlocalmemory/hooks/copilot_adapter.py +0 -208
- package/src/superlocalmemory/hooks/cross_platform_connector.py +0 -90
- package/src/superlocalmemory/hooks/cursor_adapter.py +0 -173
- package/src/superlocalmemory/hooks/hook_daemon.py +0 -295
- package/src/superlocalmemory/hooks/hook_handlers.py +0 -822
- package/src/superlocalmemory/hooks/ide_connector.py +0 -246
- package/src/superlocalmemory/hooks/memory_protocol.py +0 -158
- package/src/superlocalmemory/hooks/portable_kit.py +0 -755
- package/src/superlocalmemory/hooks/post_tool_async_hook.py +0 -183
- package/src/superlocalmemory/hooks/post_tool_outcome_hook.py +0 -351
- package/src/superlocalmemory/hooks/prewarm_auth.py +0 -187
- package/src/superlocalmemory/hooks/rules_engine.py +0 -99
- package/src/superlocalmemory/hooks/session_registry.py +0 -330
- package/src/superlocalmemory/hooks/stop_outcome_hook.py +0 -138
- package/src/superlocalmemory/hooks/sync_loop.py +0 -114
- package/src/superlocalmemory/hooks/topic_shift_hook.py +0 -302
- package/src/superlocalmemory/hooks/user_prompt_hook.py +0 -131
- package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +0 -210
- package/src/superlocalmemory/infra/__init__.py +0 -3
- package/src/superlocalmemory/infra/auth_middleware.py +0 -145
- package/src/superlocalmemory/infra/backup.py +0 -974
- package/src/superlocalmemory/infra/backup_obligations.py +0 -423
- package/src/superlocalmemory/infra/cache_manager.py +0 -267
- package/src/superlocalmemory/infra/cloud_backup.py +0 -788
- package/src/superlocalmemory/infra/daemon_identity.py +0 -300
- package/src/superlocalmemory/infra/data_root.py +0 -238
- package/src/superlocalmemory/infra/event_bus.py +0 -637
- package/src/superlocalmemory/infra/local_diagnostics.py +0 -327
- package/src/superlocalmemory/infra/pid_manager.py +0 -193
- package/src/superlocalmemory/infra/process_identity.py +0 -180
- package/src/superlocalmemory/infra/process_reaper.py +0 -624
- package/src/superlocalmemory/infra/rate_limiter.py +0 -228
- package/src/superlocalmemory/infra/self_heal.py +0 -401
- package/src/superlocalmemory/infra/version_integrity.py +0 -229
- package/src/superlocalmemory/ingestion/__init__.py +0 -13
- package/src/superlocalmemory/ingestion/adapter_manager.py +0 -255
- package/src/superlocalmemory/ingestion/base_adapter.py +0 -171
- package/src/superlocalmemory/ingestion/calendar_adapter.py +0 -349
- package/src/superlocalmemory/ingestion/credentials.py +0 -125
- package/src/superlocalmemory/ingestion/gmail_adapter.py +0 -378
- package/src/superlocalmemory/ingestion/parsers.py +0 -100
- package/src/superlocalmemory/ingestion/transcript_adapter.py +0 -161
- package/src/superlocalmemory/integrations/__init__.py +0 -1
- package/src/superlocalmemory/integrations/bounded_loops_mcp.py +0 -431
- package/src/superlocalmemory/integrations/bounded_loops_v051.py +0 -236
- package/src/superlocalmemory/learning/__init__.py +0 -0
- package/src/superlocalmemory/learning/adaptive.py +0 -172
- package/src/superlocalmemory/learning/arm_catalog.py +0 -97
- package/src/superlocalmemory/learning/assertion_miner.py +0 -403
- package/src/superlocalmemory/learning/bandit.py +0 -654
- package/src/superlocalmemory/learning/bandit_cache.py +0 -131
- package/src/superlocalmemory/learning/behavioral.py +0 -542
- package/src/superlocalmemory/learning/bootstrap.py +0 -298
- package/src/superlocalmemory/learning/consolidation_cycle.py +0 -398
- package/src/superlocalmemory/learning/consolidation_quantization_worker.py +0 -115
- package/src/superlocalmemory/learning/consolidation_worker.py +0 -261
- package/src/superlocalmemory/learning/cross_project.py +0 -408
- package/src/superlocalmemory/learning/database.py +0 -698
- package/src/superlocalmemory/learning/dedup_hnsw.py +0 -413
- package/src/superlocalmemory/learning/engagement.py +0 -487
- package/src/superlocalmemory/learning/engagement_features.py +0 -279
- package/src/superlocalmemory/learning/ensemble.py +0 -309
- package/src/superlocalmemory/learning/entity_compiler.py +0 -356
- package/src/superlocalmemory/learning/fact_outcome_joins.py +0 -207
- package/src/superlocalmemory/learning/features.py +0 -138
- package/src/superlocalmemory/learning/feedback.py +0 -724
- package/src/superlocalmemory/learning/forgetting_scheduler.py +0 -375
- package/src/superlocalmemory/learning/hnsw_dedup.py +0 -69
- package/src/superlocalmemory/learning/labeler.py +0 -85
- package/src/superlocalmemory/learning/legacy_migration.py +0 -316
- package/src/superlocalmemory/learning/lightgbm_subprocess.py +0 -236
- package/src/superlocalmemory/learning/memory_merge.py +0 -175
- package/src/superlocalmemory/learning/model_cache.py +0 -267
- package/src/superlocalmemory/learning/model_rollback.py +0 -281
- package/src/superlocalmemory/learning/outcome_queue.py +0 -306
- package/src/superlocalmemory/learning/outcomes.py +0 -286
- package/src/superlocalmemory/learning/pattern_miner.py +0 -465
- package/src/superlocalmemory/learning/pattern_miner_constants.py +0 -90
- package/src/superlocalmemory/learning/pcos.py +0 -291
- package/src/superlocalmemory/learning/project_context.py +0 -366
- package/src/superlocalmemory/learning/propensity.py +0 -131
- package/src/superlocalmemory/learning/ranker.py +0 -300
- package/src/superlocalmemory/learning/ranker_common.py +0 -163
- package/src/superlocalmemory/learning/ranker_retrain_legacy.py +0 -210
- package/src/superlocalmemory/learning/ranker_retrain_online.py +0 -423
- package/src/superlocalmemory/learning/reward.py +0 -888
- package/src/superlocalmemory/learning/reward_archive.py +0 -223
- package/src/superlocalmemory/learning/reward_boost.py +0 -211
- package/src/superlocalmemory/learning/reward_from_outcomes.py +0 -365
- package/src/superlocalmemory/learning/reward_model.py +0 -144
- package/src/superlocalmemory/learning/reward_proxy.py +0 -578
- package/src/superlocalmemory/learning/shadow_test.py +0 -524
- package/src/superlocalmemory/learning/signal_kinds.py +0 -79
- package/src/superlocalmemory/learning/signal_worker.py +0 -268
- package/src/superlocalmemory/learning/signals.py +0 -646
- package/src/superlocalmemory/learning/skill_performance_miner.py +0 -422
- package/src/superlocalmemory/learning/source_quality.py +0 -828
- package/src/superlocalmemory/learning/trigram_index.py +0 -548
- package/src/superlocalmemory/learning/workflows.py +0 -309
- package/src/superlocalmemory/llm/__init__.py +0 -0
- package/src/superlocalmemory/llm/backbone.py +0 -364
- package/src/superlocalmemory/loops/__init__.py +0 -58
- package/src/superlocalmemory/loops/budget.py +0 -58
- package/src/superlocalmemory/loops/engine.py +0 -174
- package/src/superlocalmemory/loops/ledger.py +0 -298
- package/src/superlocalmemory/loops/models.py +0 -152
- package/src/superlocalmemory/loops/rules.py +0 -52
- package/src/superlocalmemory/math/__init__.py +0 -0
- package/src/superlocalmemory/math/ebbinghaus.py +0 -352
- package/src/superlocalmemory/math/fisher.py +0 -356
- package/src/superlocalmemory/math/fisher_quantized.py +0 -255
- package/src/superlocalmemory/math/hopfield.py +0 -282
- package/src/superlocalmemory/math/langevin.py +0 -411
- package/src/superlocalmemory/math/polar_quant.py +0 -414
- package/src/superlocalmemory/math/qjl.py +0 -115
- package/src/superlocalmemory/math/sheaf.py +0 -261
- package/src/superlocalmemory/math/turbo_quant.py +0 -318
- package/src/superlocalmemory/mcp/__init__.py +0 -0
- package/src/superlocalmemory/mcp/_daemon_proxy.py +0 -203
- package/src/superlocalmemory/mcp/_pool_adapter.py +0 -181
- package/src/superlocalmemory/mcp/_stdin_guard.py +0 -60
- package/src/superlocalmemory/mcp/agent_context.py +0 -115
- package/src/superlocalmemory/mcp/cli_fallback.py +0 -602
- package/src/superlocalmemory/mcp/http_transport.py +0 -85
- package/src/superlocalmemory/mcp/profiles.py +0 -154
- package/src/superlocalmemory/mcp/resources.py +0 -281
- package/src/superlocalmemory/mcp/server.py +0 -480
- package/src/superlocalmemory/mcp/session_binding.py +0 -98
- package/src/superlocalmemory/mcp/shared.py +0 -112
- package/src/superlocalmemory/mcp/tools.py +0 -18
- package/src/superlocalmemory/mcp/tools_active.py +0 -958
- package/src/superlocalmemory/mcp/tools_brain.py +0 -298
- package/src/superlocalmemory/mcp/tools_code_graph.py +0 -1717
- package/src/superlocalmemory/mcp/tools_context.py +0 -239
- package/src/superlocalmemory/mcp/tools_core.py +0 -1112
- package/src/superlocalmemory/mcp/tools_evolution.py +0 -343
- package/src/superlocalmemory/mcp/tools_learning.py +0 -393
- package/src/superlocalmemory/mcp/tools_loops.py +0 -345
- package/src/superlocalmemory/mcp/tools_mesh.py +0 -429
- package/src/superlocalmemory/mcp/tools_ops.py +0 -115
- package/src/superlocalmemory/mcp/tools_optimize.py +0 -322
- package/src/superlocalmemory/mcp/tools_summaries.py +0 -147
- package/src/superlocalmemory/mcp/tools_v28.py +0 -292
- package/src/superlocalmemory/mcp/tools_v3.py +0 -398
- package/src/superlocalmemory/mcp/tools_v33.py +0 -507
- package/src/superlocalmemory/mesh/__init__.py +0 -12
- package/src/superlocalmemory/mesh/broker.py +0 -812
- package/src/superlocalmemory/mesh/broker_security.py +0 -470
- package/src/superlocalmemory/mesh/discovery.py +0 -365
- package/src/superlocalmemory/mesh/lock_protocol.py +0 -313
- package/src/superlocalmemory/mesh/node_identity.py +0 -97
- package/src/superlocalmemory/mesh/outbox_remote.py +0 -429
- package/src/superlocalmemory/mesh/remote_sync.py +0 -829
- package/src/superlocalmemory/mesh/state_sync.py +0 -286
- package/src/superlocalmemory/migrations/__init__.py +0 -5
- package/src/superlocalmemory/migrations/v3_4_25_to_v3_4_26.py +0 -144
- package/src/superlocalmemory/optimize/NOTICE +0 -6
- package/src/superlocalmemory/optimize/__init__.py +0 -0
- package/src/superlocalmemory/optimize/adapters/__init__.py +0 -68
- package/src/superlocalmemory/optimize/adapters/_agent_registry.py +0 -120
- package/src/superlocalmemory/optimize/adapters/anthropic_adapter.py +0 -112
- package/src/superlocalmemory/optimize/adapters/openai_adapter.py +0 -122
- package/src/superlocalmemory/optimize/adapters/wrap.py +0 -228
- package/src/superlocalmemory/optimize/cache/__init__.py +0 -31
- package/src/superlocalmemory/optimize/cache/boundary_store.py +0 -488
- package/src/superlocalmemory/optimize/cache/centroid_store.py +0 -199
- package/src/superlocalmemory/optimize/cache/context_key.py +0 -67
- package/src/superlocalmemory/optimize/cache/exact.py +0 -88
- package/src/superlocalmemory/optimize/cache/invalidation.py +0 -36
- package/src/superlocalmemory/optimize/cache/key_builder.py +0 -111
- package/src/superlocalmemory/optimize/cache/manager.py +0 -737
- package/src/superlocalmemory/optimize/cache/semantic.py +0 -637
- package/src/superlocalmemory/optimize/cache/stampede.py +0 -50
- package/src/superlocalmemory/optimize/compress/__init__.py +0 -17
- package/src/superlocalmemory/optimize/compress/align.py +0 -159
- package/src/superlocalmemory/optimize/compress/ccr.py +0 -116
- package/src/superlocalmemory/optimize/compress/prose_llmlingua.py +0 -71
- package/src/superlocalmemory/optimize/compress/router.py +0 -667
- package/src/superlocalmemory/optimize/config/__init__.py +0 -56
- package/src/superlocalmemory/optimize/config/defaults.py +0 -43
- package/src/superlocalmemory/optimize/config/schema.py +0 -327
- package/src/superlocalmemory/optimize/config/store.py +0 -270
- package/src/superlocalmemory/optimize/metrics/__init__.py +0 -8
- package/src/superlocalmemory/optimize/metrics/counters.py +0 -155
- package/src/superlocalmemory/optimize/metrics/estimator.py +0 -87
- package/src/superlocalmemory/optimize/metrics/exporters.py +0 -77
- package/src/superlocalmemory/optimize/metrics/persistence.py +0 -115
- package/src/superlocalmemory/optimize/proxy/__init__.py +0 -28
- package/src/superlocalmemory/optimize/proxy/_helpers.py +0 -730
- package/src/superlocalmemory/optimize/proxy/anthropic_surface.py +0 -375
- package/src/superlocalmemory/optimize/proxy/capture.py +0 -550
- package/src/superlocalmemory/optimize/proxy/gemini_surface.py +0 -528
- package/src/superlocalmemory/optimize/proxy/lifecycle.py +0 -126
- package/src/superlocalmemory/optimize/proxy/openai_surface.py +0 -465
- package/src/superlocalmemory/optimize/proxy/server.py +0 -199
- package/src/superlocalmemory/optimize/proxy/vertex_surface.py +0 -246
- package/src/superlocalmemory/optimize/storage/__init__.py +0 -0
- package/src/superlocalmemory/optimize/storage/db.py +0 -1185
- package/src/superlocalmemory/optimize/storage/schema.py +0 -205
- package/src/superlocalmemory/parameterization/__init__.py +0 -47
- package/src/superlocalmemory/parameterization/cross_project.py +0 -12
- package/src/superlocalmemory/parameterization/pattern_extractor.py +0 -584
- package/src/superlocalmemory/parameterization/pii_filter.py +0 -106
- package/src/superlocalmemory/parameterization/prompt_injector.py +0 -219
- package/src/superlocalmemory/parameterization/prompt_lifecycle.py +0 -281
- package/src/superlocalmemory/parameterization/soft_prompt_generator.py +0 -542
- package/src/superlocalmemory/parameterization/workflow_miner.py +0 -17
- package/src/superlocalmemory/reliability/__init__.py +0 -45
- package/src/superlocalmemory/reliability/join_liveness.py +0 -301
- package/src/superlocalmemory/reliability/prior_distance.py +0 -243
- package/src/superlocalmemory/retrieval/__init__.py +0 -0
- package/src/superlocalmemory/retrieval/agentic.py +0 -367
- package/src/superlocalmemory/retrieval/ann_index.py +0 -235
- package/src/superlocalmemory/retrieval/bm25_channel.py +0 -451
- package/src/superlocalmemory/retrieval/bridge_discovery.py +0 -253
- package/src/superlocalmemory/retrieval/channel_registry.py +0 -154
- package/src/superlocalmemory/retrieval/channel_status.py +0 -117
- package/src/superlocalmemory/retrieval/engine.py +0 -1615
- package/src/superlocalmemory/retrieval/entity_channel.py +0 -994
- package/src/superlocalmemory/retrieval/forgetting_filter.py +0 -160
- package/src/superlocalmemory/retrieval/fusion.py +0 -81
- package/src/superlocalmemory/retrieval/graph_adjacency.py +0 -219
- package/src/superlocalmemory/retrieval/hopfield_channel.py +0 -465
- package/src/superlocalmemory/retrieval/profile_channel.py +0 -105
- package/src/superlocalmemory/retrieval/quantization_aware_search.py +0 -147
- package/src/superlocalmemory/retrieval/remote_reranker.py +0 -758
- package/src/superlocalmemory/retrieval/reranker.py +0 -674
- package/src/superlocalmemory/retrieval/scope_policy.py +0 -126
- package/src/superlocalmemory/retrieval/semantic_channel.py +0 -638
- package/src/superlocalmemory/retrieval/spreading.py +0 -288
- package/src/superlocalmemory/retrieval/spreading_activation.py +0 -616
- package/src/superlocalmemory/retrieval/strategy.py +0 -248
- package/src/superlocalmemory/retrieval/temporal_channel.py +0 -433
- package/src/superlocalmemory/retrieval/temporal_frame.py +0 -102
- package/src/superlocalmemory/retrieval/temporal_utils.py +0 -122
- package/src/superlocalmemory/retrieval/temporal_validity_filter.py +0 -499
- package/src/superlocalmemory/retrieval/time_window.py +0 -181
- package/src/superlocalmemory/retrieval/vector_store.py +0 -863
- package/src/superlocalmemory/server/__init__.py +0 -1
- package/src/superlocalmemory/server/api.py +0 -310
- package/src/superlocalmemory/server/asset_versions.py +0 -171
- package/src/superlocalmemory/server/bandit_loops.py +0 -158
- package/src/superlocalmemory/server/config_file.py +0 -90
- package/src/superlocalmemory/server/consolidation_runner.py +0 -140
- package/src/superlocalmemory/server/egress_policy.py +0 -258
- package/src/superlocalmemory/server/loopback.py +0 -85
- package/src/superlocalmemory/server/middleware/__init__.py +0 -11
- package/src/superlocalmemory/server/middleware/security_headers.py +0 -144
- package/src/superlocalmemory/server/origin.py +0 -55
- package/src/superlocalmemory/server/profile_runtime.py +0 -515
- package/src/superlocalmemory/server/rbac_enforce.py +0 -194
- package/src/superlocalmemory/server/recall_health.py +0 -343
- package/src/superlocalmemory/server/recall_serializer.py +0 -320
- package/src/superlocalmemory/server/route_mutations.py +0 -104
- package/src/superlocalmemory/server/routes/__init__.py +0 -4
- package/src/superlocalmemory/server/routes/abstraction.py +0 -314
- package/src/superlocalmemory/server/routes/adapters.py +0 -63
- package/src/superlocalmemory/server/routes/agents.py +0 -303
- package/src/superlocalmemory/server/routes/backup.py +0 -869
- package/src/superlocalmemory/server/routes/behavioral.py +0 -659
- package/src/superlocalmemory/server/routes/brain.py +0 -1892
- package/src/superlocalmemory/server/routes/chat.py +0 -393
- package/src/superlocalmemory/server/routes/compliance.py +0 -533
- package/src/superlocalmemory/server/routes/config_api.py +0 -703
- package/src/superlocalmemory/server/routes/data_io.py +0 -329
- package/src/superlocalmemory/server/routes/entity.py +0 -237
- package/src/superlocalmemory/server/routes/events.py +0 -214
- package/src/superlocalmemory/server/routes/evolution.py +0 -510
- package/src/superlocalmemory/server/routes/helpers.py +0 -499
- package/src/superlocalmemory/server/routes/ingest.py +0 -137
- package/src/superlocalmemory/server/routes/insights.py +0 -366
- package/src/superlocalmemory/server/routes/learning.py +0 -834
- package/src/superlocalmemory/server/routes/learning_telemetry.py +0 -154
- package/src/superlocalmemory/server/routes/lifecycle.py +0 -184
- package/src/superlocalmemory/server/routes/memories.py +0 -1661
- package/src/superlocalmemory/server/routes/mesh.py +0 -517
- package/src/superlocalmemory/server/routes/mesh_lock.py +0 -54
- package/src/superlocalmemory/server/routes/mesh_state.py +0 -63
- package/src/superlocalmemory/server/routes/optimize.py +0 -197
- package/src/superlocalmemory/server/routes/prewarm.py +0 -173
- package/src/superlocalmemory/server/routes/profiles.py +0 -292
- package/src/superlocalmemory/server/routes/ratelimit.py +0 -132
- package/src/superlocalmemory/server/routes/rbac.py +0 -366
- package/src/superlocalmemory/server/routes/stats.py +0 -385
- package/src/superlocalmemory/server/routes/tiers.py +0 -222
- package/src/superlocalmemory/server/routes/timeline.py +0 -258
- package/src/superlocalmemory/server/routes/token.py +0 -90
- package/src/superlocalmemory/server/routes/v3_api.py +0 -3023
- package/src/superlocalmemory/server/routes/ws.py +0 -171
- package/src/superlocalmemory/server/security_middleware.py +0 -89
- package/src/superlocalmemory/server/ui.py +0 -354
- package/src/superlocalmemory/server/unified_daemon.py +0 -6326
- package/src/superlocalmemory/server/write_identity.py +0 -195
- package/src/superlocalmemory/storage/__init__.py +0 -0
- package/src/superlocalmemory/storage/_migration_internals.py +0 -638
- package/src/superlocalmemory/storage/_schema_version.py +0 -174
- package/src/superlocalmemory/storage/access_log.py +0 -170
- package/src/superlocalmemory/storage/admission_codec.py +0 -129
- package/src/superlocalmemory/storage/admission_journal.py +0 -843
- package/src/superlocalmemory/storage/agent_experience.py +0 -546
- package/src/superlocalmemory/storage/backup.py +0 -531
- package/src/superlocalmemory/storage/correction_cases.py +0 -670
- package/src/superlocalmemory/storage/database.py +0 -3180
- package/src/superlocalmemory/storage/deferred_writes.py +0 -209
- package/src/superlocalmemory/storage/embedding_codec.py +0 -200
- package/src/superlocalmemory/storage/embedding_migrator.py +0 -672
- package/src/superlocalmemory/storage/erasure_fence.py +0 -45
- package/src/superlocalmemory/storage/execution_learning.py +0 -285
- package/src/superlocalmemory/storage/external_evidence.py +0 -359
- package/src/superlocalmemory/storage/generation_fence.py +0 -63
- package/src/superlocalmemory/storage/lineage_retention.py +0 -236
- package/src/superlocalmemory/storage/logical_edges.py +0 -86
- package/src/superlocalmemory/storage/memory_write.py +0 -115
- package/src/superlocalmemory/storage/migration_runner.py +0 -895
- package/src/superlocalmemory/storage/migration_v33.py +0 -140
- package/src/superlocalmemory/storage/migrations/M001_add_signal_features_columns.py +0 -67
- package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +0 -107
- package/src/superlocalmemory/storage/migrations/M003_migration_log.py +0 -38
- package/src/superlocalmemory/storage/migrations/M004_cross_platform_sync_log.py +0 -46
- package/src/superlocalmemory/storage/migrations/M005_bandit_tables.py +0 -75
- package/src/superlocalmemory/storage/migrations/M006_action_outcomes_reward.py +0 -75
- package/src/superlocalmemory/storage/migrations/M007_pending_outcomes.py +0 -63
- package/src/superlocalmemory/storage/migrations/M009_model_lineage.py +0 -94
- package/src/superlocalmemory/storage/migrations/M010_evolution_config.py +0 -80
- package/src/superlocalmemory/storage/migrations/M011_archive_and_merge.py +0 -87
- package/src/superlocalmemory/storage/migrations/M012_shadow_observations.py +0 -72
- package/src/superlocalmemory/storage/migrations/M013_bi_temporal_columns.py +0 -55
- package/src/superlocalmemory/storage/migrations/M014_v345_scale_ready.py +0 -45
- package/src/superlocalmemory/storage/migrations/M015_add_pinned_column.py +0 -58
- package/src/superlocalmemory/storage/migrations/M016_add_scope_support.py +0 -120
- package/src/superlocalmemory/storage/migrations/M017_ccq_scope_column.py +0 -79
- package/src/superlocalmemory/storage/migrations/M018_ingestion_operations.py +0 -120
- package/src/superlocalmemory/storage/migrations/M019_derivation_lineage.py +0 -54
- package/src/superlocalmemory/storage/migrations/M020_model_state_integrity.py +0 -52
- package/src/superlocalmemory/storage/migrations/M021_ingestion_log_profile.py +0 -108
- package/src/superlocalmemory/storage/migrations/M022_entity_aliases_profile.py +0 -86
- package/src/superlocalmemory/storage/migrations/M023_mesh_profile_isolation.py +0 -194
- package/src/superlocalmemory/storage/migrations/M024_rbac_users_roles.py +0 -87
- package/src/superlocalmemory/storage/migrations/M025_perf_indexes.py +0 -90
- package/src/superlocalmemory/storage/migrations/M026_rbac_memberships_fk.py +0 -136
- package/src/superlocalmemory/storage/migrations/M027_transferable_patterns_profile.py +0 -163
- package/src/superlocalmemory/storage/migrations/M028_fact_entity_associations.py +0 -305
- package/src/superlocalmemory/storage/migrations/M029_behavioral_history_indexes.py +0 -137
- package/src/superlocalmemory/storage/migrations/M030_entity_explorer_indexes.py +0 -93
- package/src/superlocalmemory/storage/migrations/M031_dead_letter_operations.py +0 -80
- package/src/superlocalmemory/storage/migrations/M032_write_coordinator_admission.py +0 -188
- package/src/superlocalmemory/storage/migrations/M033_projection_transactions.py +0 -148
- package/src/superlocalmemory/storage/migrations/M034_obligation_integrity.py +0 -58
- package/src/superlocalmemory/storage/migrations/M035_erasure_receipts.py +0 -113
- package/src/superlocalmemory/storage/migrations/M036_vector_row_map.py +0 -107
- package/src/superlocalmemory/storage/migrations/M037_manifest_hmac_version.py +0 -162
- package/src/superlocalmemory/storage/migrations/M038_learning_feedback_channel.py +0 -77
- package/src/superlocalmemory/storage/migrations/M039_scene_fact_members.py +0 -137
- package/src/superlocalmemory/storage/migrations/M040_agent_experience_receipts.py +0 -254
- package/src/superlocalmemory/storage/migrations/M041_external_evidence_receipts.py +0 -189
- package/src/superlocalmemory/storage/migrations/M042_correction_case_ledger.py +0 -245
- package/src/superlocalmemory/storage/migrations/M043_quarantine_display_summaries.py +0 -512
- package/src/superlocalmemory/storage/migrations/M044_play_carries_its_own_evidence.py +0 -127
- package/src/superlocalmemory/storage/migrations/M045_fact_outcome_score.py +0 -158
- package/src/superlocalmemory/storage/migrations/M046_prospective_memory_has_its_own_name.py +0 -620
- package/src/superlocalmemory/storage/migrations/M047_fisher_vectors_are_stored_like_every_other_vector.py +0 -306
- package/src/superlocalmemory/storage/migrations/M048_upcoming_holds_only_what_is_upcoming.py +0 -229
- package/src/superlocalmemory/storage/migrations/M049_a_schema_version_marker_is_one_row.py +0 -201
- package/src/superlocalmemory/storage/migrations/M050_execution_learning_v2.py +0 -70
- package/src/superlocalmemory/storage/migrations/__init__.py +0 -103
- package/src/superlocalmemory/storage/migrations.py +0 -333
- package/src/superlocalmemory/storage/models.py +0 -500
- package/src/superlocalmemory/storage/projection_outbox.py +0 -346
- package/src/superlocalmemory/storage/quantized_store.py +0 -280
- package/src/superlocalmemory/storage/read_connection.py +0 -115
- package/src/superlocalmemory/storage/retention_policy.py +0 -860
- package/src/superlocalmemory/storage/schema.py +0 -1108
- package/src/superlocalmemory/storage/schema_code_graph.py +0 -282
- package/src/superlocalmemory/storage/schema_v32.py +0 -382
- package/src/superlocalmemory/storage/schema_v3410.py +0 -159
- package/src/superlocalmemory/storage/schema_v3411.py +0 -149
- package/src/superlocalmemory/storage/schema_v343.py +0 -315
- package/src/superlocalmemory/storage/schema_v345.py +0 -109
- package/src/superlocalmemory/storage/schema_v347.py +0 -140
- package/src/superlocalmemory/storage/sqlite_vectors.py +0 -169
- package/src/superlocalmemory/storage/v2_migrator.py +0 -466
- package/src/superlocalmemory/storage/write_coordinator.py +0 -949
- package/src/superlocalmemory/storage/write_lock.py +0 -88
- package/src/superlocalmemory/summaries/__init__.py +0 -37
- package/src/superlocalmemory/summaries/base.py +0 -267
- package/src/superlocalmemory/summaries/daily_reflection.py +0 -340
- package/src/superlocalmemory/summaries/non_answer.py +0 -223
- package/src/superlocalmemory/summaries/project_work_log.py +0 -440
- package/src/superlocalmemory/summaries/session_summary.py +0 -311
- package/src/superlocalmemory/trust/__init__.py +0 -0
- package/src/superlocalmemory/trust/gate.py +0 -171
- package/src/superlocalmemory/trust/provenance.py +0 -124
- package/src/superlocalmemory/trust/scorer.py +0 -413
- package/src/superlocalmemory/trust/signals.py +0 -153
- package/src/superlocalmemory/ui/assets/slm-icon-white.svg +0 -64
- package/src/superlocalmemory/ui/assets/slm-icon.svg +0 -36
- package/src/superlocalmemory/ui/css/brain.css +0 -409
- package/src/superlocalmemory/ui/css/design-system.css +0 -696
- package/src/superlocalmemory/ui/css/legacy-dashboard.css +0 -663
- package/src/superlocalmemory/ui/css/neural-glass.css +0 -1599
- package/src/superlocalmemory/ui/css/od-bridge.css +0 -158
- package/src/superlocalmemory/ui/favicon.svg +0 -36
- package/src/superlocalmemory/ui/index.html +0 -1638
- package/src/superlocalmemory/ui/js/agents.js +0 -192
- package/src/superlocalmemory/ui/js/auto-settings.js +0 -624
- package/src/superlocalmemory/ui/js/brain.js +0 -1400
- package/src/superlocalmemory/ui/js/clusters.js +0 -326
- package/src/superlocalmemory/ui/js/compliance.js +0 -307
- package/src/superlocalmemory/ui/js/core.js +0 -566
- package/src/superlocalmemory/ui/js/dashboard.js +0 -503
- package/src/superlocalmemory/ui/js/event-delegation.js +0 -113
- package/src/superlocalmemory/ui/js/events.js +0 -178
- package/src/superlocalmemory/ui/js/fact-detail.js +0 -142
- package/src/superlocalmemory/ui/js/feedback.js +0 -339
- package/src/superlocalmemory/ui/js/graph-event-bus.js +0 -83
- package/src/superlocalmemory/ui/js/graph-filters.js +0 -220
- package/src/superlocalmemory/ui/js/graph-ui.js +0 -214
- package/src/superlocalmemory/ui/js/ide-status.js +0 -115
- package/src/superlocalmemory/ui/js/init.js +0 -54
- package/src/superlocalmemory/ui/js/knowledge-graph.js +0 -945
- package/src/superlocalmemory/ui/js/lifecycle.js +0 -387
- package/src/superlocalmemory/ui/js/math-health.js +0 -114
- package/src/superlocalmemory/ui/js/memories.js +0 -394
- package/src/superlocalmemory/ui/js/memory-chat.js +0 -371
- package/src/superlocalmemory/ui/js/memory-timeline.js +0 -265
- package/src/superlocalmemory/ui/js/modal.js +0 -733
- package/src/superlocalmemory/ui/js/ng-entities.js +0 -298
- package/src/superlocalmemory/ui/js/ng-health.js +0 -208
- package/src/superlocalmemory/ui/js/ng-ingestion.js +0 -203
- package/src/superlocalmemory/ui/js/ng-mesh.js +0 -374
- package/src/superlocalmemory/ui/js/ng-shell.js +0 -524
- package/src/superlocalmemory/ui/js/ng-skills.js +0 -663
- package/src/superlocalmemory/ui/js/od-agents.js +0 -588
- package/src/superlocalmemory/ui/js/od-auth-gate.js +0 -257
- package/src/superlocalmemory/ui/js/od-backup.js +0 -878
- package/src/superlocalmemory/ui/js/od-boundedloops.js +0 -324
- package/src/superlocalmemory/ui/js/od-brain.js +0 -1095
- package/src/superlocalmemory/ui/js/od-compliance-ext.js +0 -301
- package/src/superlocalmemory/ui/js/od-components.js +0 -147
- package/src/superlocalmemory/ui/js/od-entities.js +0 -622
- package/src/superlocalmemory/ui/js/od-graph.js +0 -776
- package/src/superlocalmemory/ui/js/od-health.js +0 -579
- package/src/superlocalmemory/ui/js/od-mcp.js +0 -508
- package/src/superlocalmemory/ui/js/od-memories.js +0 -1499
- package/src/superlocalmemory/ui/js/od-mesh.js +0 -645
- package/src/superlocalmemory/ui/js/od-operations.js +0 -1268
- package/src/superlocalmemory/ui/js/od-ops-health.js +0 -417
- package/src/superlocalmemory/ui/js/od-optimize.js +0 -828
- package/src/superlocalmemory/ui/js/od-settings.js +0 -1275
- package/src/superlocalmemory/ui/js/od-shell.js +0 -819
- package/src/superlocalmemory/ui/js/od-skills.js +0 -600
- package/src/superlocalmemory/ui/js/od-team.js +0 -265
- package/src/superlocalmemory/ui/js/optimize.js +0 -191
- package/src/superlocalmemory/ui/js/profiles.js +0 -362
- package/src/superlocalmemory/ui/js/quick-actions.js +0 -334
- package/src/superlocalmemory/ui/js/recall-lab.js +0 -373
- package/src/superlocalmemory/ui/js/search.js +0 -86
- package/src/superlocalmemory/ui/js/settings.js +0 -556
- package/src/superlocalmemory/ui/js/timeline.js +0 -62
- package/src/superlocalmemory/ui/js/trust-dashboard.js +0 -225
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/bootstrap-icons.css +0 -2018
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff +0 -0
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/bootstrap.bundle.min.js +0 -7
- package/src/superlocalmemory/ui/vendor/bootstrap.min.css +0 -6
- package/src/superlocalmemory/ui/vendor/d3.v7.min.js +0 -2
- package/src/superlocalmemory/ui/vendor/graphology-library.min.js +0 -2
- package/src/superlocalmemory/ui/vendor/graphology.umd.min.js +0 -2
- package/src/superlocalmemory/ui/vendor/inter-ui/inter-variable.min.css +0 -8
- package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable-Italic.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/sigma.min.js +0 -1
- package/src/superlocalmemory/vector/__init__.py +0 -9
- package/src/superlocalmemory/vector/lancedb_backend.py +0 -366
|
@@ -1,1112 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
-
# Licensed under AGPL-3.0-or-later - see LICENSE file
|
|
3
|
-
# Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
|
|
4
|
-
|
|
5
|
-
"""SuperLocalMemory V3 — Core MCP Tools (13 tools).
|
|
6
|
-
|
|
7
|
-
remember, recall, search, fetch, list_recent, get_status, build_graph,
|
|
8
|
-
switch_profile, backup_status, memory_used, get_learned_patterns,
|
|
9
|
-
correct_pattern, get_attribution.
|
|
10
|
-
|
|
11
|
-
Part of Qualixar | Author: Varun Pratap Bhardwaj
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
from __future__ import annotations
|
|
15
|
-
|
|
16
|
-
import hashlib
|
|
17
|
-
import logging
|
|
18
|
-
from typing import Callable
|
|
19
|
-
|
|
20
|
-
from mcp.types import ToolAnnotations
|
|
21
|
-
|
|
22
|
-
from superlocalmemory.core.admission import admits
|
|
23
|
-
from superlocalmemory.core.config import CANONICAL_LIST_LIMIT, CANONICAL_RECALL_LIMIT
|
|
24
|
-
from superlocalmemory.core.operation_request import OperationKind
|
|
25
|
-
from superlocalmemory.infra.data_root import state_path
|
|
26
|
-
from superlocalmemory.mcp._daemon_proxy import daemon_unavailable_error
|
|
27
|
-
from superlocalmemory.mcp.shared import authorize_mcp_mutation
|
|
28
|
-
|
|
29
|
-
logger = logging.getLogger(__name__)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def _projection_queue_depth(db: object) -> int:
|
|
33
|
-
"""Facts queued for the graph and vector projections, or 0 when there are none.
|
|
34
|
-
|
|
35
|
-
Imported inside the function: this module is loaded on every MCP start over
|
|
36
|
-
stdio, where import cost is startup latency a user feels.
|
|
37
|
-
"""
|
|
38
|
-
try:
|
|
39
|
-
from superlocalmemory.storage import projection_outbox
|
|
40
|
-
return projection_outbox.depth(db)
|
|
41
|
-
except Exception:
|
|
42
|
-
return 0
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
async def _runtime_profile(get_engine: Callable, explicit: str = "") -> str:
|
|
46
|
-
"""Resolve an MCP default profile from daemon runtime truth."""
|
|
47
|
-
if explicit:
|
|
48
|
-
return explicit
|
|
49
|
-
import asyncio
|
|
50
|
-
|
|
51
|
-
try:
|
|
52
|
-
from superlocalmemory.cli.daemon import daemon_request, is_daemon_running
|
|
53
|
-
|
|
54
|
-
if await asyncio.to_thread(is_daemon_running):
|
|
55
|
-
status = await asyncio.to_thread(daemon_request, "GET", "/status")
|
|
56
|
-
if isinstance(status, dict) and status.get("profile"):
|
|
57
|
-
return str(status["profile"])
|
|
58
|
-
raise RuntimeError("resident daemon did not report its active profile")
|
|
59
|
-
except RuntimeError:
|
|
60
|
-
raise
|
|
61
|
-
except Exception as exc:
|
|
62
|
-
logger.debug("daemon profile resolution failed: %s", exc)
|
|
63
|
-
return str(get_engine().profile_id)
|
|
64
|
-
|
|
65
|
-
def _emit_event(event_type: str, payload: dict | None = None,
|
|
66
|
-
source_agent: str = "mcp_client") -> None:
|
|
67
|
-
"""Emit an event to the EventBus (best-effort, never raises)."""
|
|
68
|
-
try:
|
|
69
|
-
from superlocalmemory.infra.event_bus import EventBus
|
|
70
|
-
bus = EventBus.get_instance(str(state_path("memory.db")))
|
|
71
|
-
bus.emit(event_type, payload=payload, source_agent=source_agent,
|
|
72
|
-
source_protocol="mcp")
|
|
73
|
-
except Exception:
|
|
74
|
-
pass
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def register_core_tools(server, get_engine: Callable) -> None:
|
|
78
|
-
"""Register the 13 core MCP tools on *server*."""
|
|
79
|
-
|
|
80
|
-
@server.tool()
|
|
81
|
-
@admits(OperationKind.REMEMBER)
|
|
82
|
-
async def remember(
|
|
83
|
-
content: str, tags: str = "", project: str = "",
|
|
84
|
-
importance: int = 5, session_id: str = "",
|
|
85
|
-
agent_id: str = "mcp_client",
|
|
86
|
-
scope: str | None = None,
|
|
87
|
-
shared_with: str = "",
|
|
88
|
-
idempotency_key: str = "",
|
|
89
|
-
session_date: str = "",
|
|
90
|
-
) -> dict:
|
|
91
|
-
"""Store content to memory with intelligent indexing.
|
|
92
|
-
|
|
93
|
-
Extracts atomic facts, resolves entities, builds graph edges,
|
|
94
|
-
and indexes for hybrid retrieval with graph-aware enhancement.
|
|
95
|
-
|
|
96
|
-
Multi-scope: ``scope`` sets visibility (personal/shared/global).
|
|
97
|
-
``shared_with`` is a comma-separated list of profile_ids for
|
|
98
|
-
shared scope.
|
|
99
|
-
|
|
100
|
-
``session_date`` says WHEN the memory is about, as opposed to when it
|
|
101
|
-
was written. Omit it and the memory is dated today, which is what every
|
|
102
|
-
memory got before 4.0.10 because there was no way to say otherwise.
|
|
103
|
-
Accepts YYYY-MM-DD or a full ISO 8601 timestamp.
|
|
104
|
-
"""
|
|
105
|
-
# v3.6.10: resolve "mcp_client" sentinel → URL path (HTTP) or env var (stdio)
|
|
106
|
-
if agent_id == "mcp_client":
|
|
107
|
-
from superlocalmemory.mcp.agent_context import get_current_agent_id
|
|
108
|
-
agent_id = get_current_agent_id()
|
|
109
|
-
# Bind the write to a session the same way the read path does.
|
|
110
|
-
#
|
|
111
|
-
# recall has resolved this through a four-step ladder since S9-DASH-10;
|
|
112
|
-
# remember stored whatever it was handed, which for a caller that does
|
|
113
|
-
# not pass one is nothing. Result on the author's store: 192 of 3,894
|
|
114
|
-
# facts carry a session_id (4.9%). The engine's session-diversity
|
|
115
|
-
# promotion cannot promote a fact with no session, so it was running
|
|
116
|
-
# against a corpus where 95% of rows looked like the same session.
|
|
117
|
-
#
|
|
118
|
-
# allow_agent_fallback is OFF here, unlike recall. `mcp:<agent_id>` is a
|
|
119
|
-
# useful key for settling one outcome; as a stored session_id it would
|
|
120
|
-
# file every memory an agent ever wrote under one session, and diversity
|
|
121
|
-
# promotion would then treat a whole history as a single conversation —
|
|
122
|
-
# worse than the empty string it replaces.
|
|
123
|
-
from superlocalmemory.mcp.session_binding import resolve_session_id
|
|
124
|
-
|
|
125
|
-
session_id = resolve_session_id(
|
|
126
|
-
session_id, agent_id=agent_id, allow_agent_fallback=False,
|
|
127
|
-
)
|
|
128
|
-
meta = {
|
|
129
|
-
"project": project,
|
|
130
|
-
"importance": importance,
|
|
131
|
-
"agent_id": agent_id,
|
|
132
|
-
"session_id": session_id,
|
|
133
|
-
}
|
|
134
|
-
effective_idempotency_key = idempotency_key
|
|
135
|
-
if not effective_idempotency_key:
|
|
136
|
-
# Derive a stable key before the first attempt so every retry of
|
|
137
|
-
# the same logical call carries the same key. When a session token
|
|
138
|
-
# is present it is included in the material to keep per-session
|
|
139
|
-
# stores separate. Without a session token the key is derived from
|
|
140
|
-
# the remaining call parameters so repeated observations with the
|
|
141
|
-
# same content, agent, and scope are deduplicated across retries.
|
|
142
|
-
if session_id:
|
|
143
|
-
material = (
|
|
144
|
-
f"{agent_id}\0{session_id}\0{scope or ''}\0{shared_with}\0{content}"
|
|
145
|
-
)
|
|
146
|
-
effective_idempotency_key = "mcp:" + hashlib.sha256(
|
|
147
|
-
material.encode("utf-8")
|
|
148
|
-
).hexdigest()
|
|
149
|
-
else:
|
|
150
|
-
material = f"{agent_id}\0{scope or ''}\0{shared_with}\0{content}"
|
|
151
|
-
effective_idempotency_key = "mcp:req:" + hashlib.sha256(
|
|
152
|
-
material.encode("utf-8")
|
|
153
|
-
).hexdigest()
|
|
154
|
-
# Parse shared_with from comma-separated string
|
|
155
|
-
_shared_list = [s.strip() for s in shared_with.split(",") if s.strip()] if shared_with else None
|
|
156
|
-
# v3.5.5 WRITE-THROUGH: route through the daemon's /remember, which does
|
|
157
|
-
# a synchronous verbatim insert (memory is keyword/BM25-recallable the
|
|
158
|
-
# instant this returns) and enqueues async enrichment. This closes the
|
|
159
|
-
# recall window so a parallel/next agent finds memories saved seconds ago.
|
|
160
|
-
# Falls back to the capability-owned worker only if the daemon is
|
|
161
|
-
# unreachable. Raw pending.db writes are legacy replay input only.
|
|
162
|
-
daemon_owned = False
|
|
163
|
-
try:
|
|
164
|
-
import asyncio as _asyncio
|
|
165
|
-
|
|
166
|
-
from superlocalmemory.cli.daemon import daemon_request, is_daemon_running
|
|
167
|
-
# is_daemon_running() and daemon_request() both use blocking urllib
|
|
168
|
-
# against the same uvicorn server — run in threads so the MCP
|
|
169
|
-
# event loop stays unblocked (#34 class bug).
|
|
170
|
-
daemon_owned = await _asyncio.to_thread(is_daemon_running)
|
|
171
|
-
if daemon_owned:
|
|
172
|
-
# A positively identified daemon owns this database. Never
|
|
173
|
-
# spawn a WorkerPool writer after a transient daemon failure:
|
|
174
|
-
# that creates the competing writers which SQLite WAL cannot
|
|
175
|
-
# support. Retry the canonical path, then return an explicit
|
|
176
|
-
# retryable result to the MCP client.
|
|
177
|
-
for attempt in range(3):
|
|
178
|
-
resp = await _asyncio.to_thread(daemon_request, "POST", "/remember", {
|
|
179
|
-
"content": content, "tags": tags, "metadata": meta,
|
|
180
|
-
"scope": scope, "shared_with": _shared_list,
|
|
181
|
-
"session_id": session_id,
|
|
182
|
-
"session_date": session_date,
|
|
183
|
-
"idempotency_key": effective_idempotency_key or None,
|
|
184
|
-
})
|
|
185
|
-
if resp and (resp.get("fact_ids") is not None or resp.get("ok")):
|
|
186
|
-
fids = resp.get("fact_ids") or []
|
|
187
|
-
materialization_state = resp.get("materialization_state")
|
|
188
|
-
if materialization_state is None:
|
|
189
|
-
materialization_state = (
|
|
190
|
-
"complete" if resp.get("status") == "stored" else "queryable"
|
|
191
|
-
)
|
|
192
|
-
pending = materialization_state != "complete"
|
|
193
|
-
return {
|
|
194
|
-
"success": True,
|
|
195
|
-
"fact_ids": fids,
|
|
196
|
-
"count": int(resp.get("count", len(fids))),
|
|
197
|
-
"pending": pending,
|
|
198
|
-
"pending_id": resp.get("pending_id") if pending else None,
|
|
199
|
-
"operation_id": resp.get("operation_id"),
|
|
200
|
-
"materialization_state": materialization_state,
|
|
201
|
-
"message": (
|
|
202
|
-
"Stored through canonical daemon ingestion."
|
|
203
|
-
if not pending
|
|
204
|
-
else "Queryable now; canonical enrichment is still running."
|
|
205
|
-
),
|
|
206
|
-
}
|
|
207
|
-
if attempt < 2:
|
|
208
|
-
await _asyncio.sleep(0.05 * (attempt + 1))
|
|
209
|
-
return {
|
|
210
|
-
"success": False,
|
|
211
|
-
"code": "DAEMON_UNAVAILABLE",
|
|
212
|
-
"retryable": True,
|
|
213
|
-
"error": (
|
|
214
|
-
daemon_unavailable_error()
|
|
215
|
-
),
|
|
216
|
-
}
|
|
217
|
-
except Exception as dexc:
|
|
218
|
-
logger.debug("MCP remember via daemon failed, pending fallback: %s", dexc)
|
|
219
|
-
if daemon_owned:
|
|
220
|
-
return {
|
|
221
|
-
"success": False,
|
|
222
|
-
"code": "DAEMON_UNAVAILABLE",
|
|
223
|
-
"retryable": True,
|
|
224
|
-
"error": (
|
|
225
|
-
daemon_unavailable_error()
|
|
226
|
-
),
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
try:
|
|
230
|
-
import asyncio as _asyncio
|
|
231
|
-
|
|
232
|
-
from superlocalmemory.mcp._daemon_proxy import choose_pool
|
|
233
|
-
|
|
234
|
-
worker_meta = {
|
|
235
|
-
**meta,
|
|
236
|
-
"tags": tags,
|
|
237
|
-
"scope": scope or "personal",
|
|
238
|
-
"shared_with": _shared_list or [],
|
|
239
|
-
"idempotency_key": (
|
|
240
|
-
effective_idempotency_key
|
|
241
|
-
or "mcp:" + hashlib.sha256(content.encode("utf-8")).hexdigest()
|
|
242
|
-
),
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
def _store_via_daemon_pool():
|
|
246
|
-
pool = choose_pool()
|
|
247
|
-
return pool.store(content, worker_meta)
|
|
248
|
-
|
|
249
|
-
stored = await _asyncio.to_thread(_store_via_daemon_pool)
|
|
250
|
-
if not isinstance(stored, dict) or not stored.get("ok"):
|
|
251
|
-
if isinstance(stored, dict) and stored.get("code") == "DAEMON_UNAVAILABLE":
|
|
252
|
-
return {
|
|
253
|
-
"success": False,
|
|
254
|
-
"code": "DAEMON_UNAVAILABLE",
|
|
255
|
-
"retryable": True,
|
|
256
|
-
"error": stored.get(
|
|
257
|
-
"error",
|
|
258
|
-
daemon_unavailable_error(),
|
|
259
|
-
),
|
|
260
|
-
}
|
|
261
|
-
return {
|
|
262
|
-
"success": False,
|
|
263
|
-
"code": "DAEMON_UNAVAILABLE",
|
|
264
|
-
"retryable": True,
|
|
265
|
-
"error": daemon_unavailable_error(),
|
|
266
|
-
}
|
|
267
|
-
fact_ids = list(stored.get("fact_ids") or [])
|
|
268
|
-
materialization_state = str(
|
|
269
|
-
stored.get("materialization_state") or "complete"
|
|
270
|
-
)
|
|
271
|
-
allowed_states = {"queryable", "enriching", "complete"}
|
|
272
|
-
if materialization_state not in allowed_states:
|
|
273
|
-
raise RuntimeError(
|
|
274
|
-
"canonical worker returned invalid materialization state: "
|
|
275
|
-
f"{materialization_state}"
|
|
276
|
-
)
|
|
277
|
-
pending = materialization_state != "complete"
|
|
278
|
-
operation_id = stored.get("operation_id")
|
|
279
|
-
pending_id = stored.get("pending_id")
|
|
280
|
-
if pending and pending_id is None:
|
|
281
|
-
pending_id = operation_id
|
|
282
|
-
return {
|
|
283
|
-
"success": True,
|
|
284
|
-
"fact_ids": fact_ids,
|
|
285
|
-
"count": int(stored.get("count", len(fact_ids))),
|
|
286
|
-
"pending": pending,
|
|
287
|
-
"pending_id": pending_id if pending else None,
|
|
288
|
-
"operation_id": operation_id,
|
|
289
|
-
"materialization_state": materialization_state,
|
|
290
|
-
"message": (
|
|
291
|
-
"Stored through canonical local ingestion."
|
|
292
|
-
if not pending
|
|
293
|
-
else "Queryable now; canonical enrichment is still running."
|
|
294
|
-
),
|
|
295
|
-
}
|
|
296
|
-
except Exception:
|
|
297
|
-
logger.exception("remember failed")
|
|
298
|
-
return {
|
|
299
|
-
"success": False,
|
|
300
|
-
"code": "DAEMON_UNAVAILABLE",
|
|
301
|
-
"retryable": True,
|
|
302
|
-
"error": daemon_unavailable_error(),
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
@server.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
306
|
-
@admits(OperationKind.RECALL)
|
|
307
|
-
async def recall(
|
|
308
|
-
query: str, limit: int = CANONICAL_RECALL_LIMIT, agent_id: str = "mcp_client",
|
|
309
|
-
session_id: str = "", fast: bool | None = None,
|
|
310
|
-
include_global: bool | None = None,
|
|
311
|
-
include_shared: bool | None = None,
|
|
312
|
-
window: str = "",
|
|
313
|
-
as_of: str | None = None,
|
|
314
|
-
known_as_of: str | None = None,
|
|
315
|
-
valid_at: str | None = None,
|
|
316
|
-
include_unknown: bool = False,
|
|
317
|
-
) -> dict:
|
|
318
|
-
"""Search memories through hybrid retrieval, RRF fusion, and reranking.
|
|
319
|
-
|
|
320
|
-
Fast local retrieval (six channels + reranker) returns in ~1-2s. This
|
|
321
|
-
tool does NOT run an internal LLM reformulation round — YOU (the calling
|
|
322
|
-
model) are the reasoner. Drive refinement using the confidence signals
|
|
323
|
-
in the response:
|
|
324
|
-
• ``no_confident_match: true`` → nothing cleared the evidence floor.
|
|
325
|
-
Do NOT invent a memory. Rewrite the query into 1-3 more specific
|
|
326
|
-
sub-queries (split multi-hop questions; try entity names, synonyms,
|
|
327
|
-
or a broader phrasing) and call ``recall`` again before concluding
|
|
328
|
-
the information is unknown.
|
|
329
|
-
• ``answer_confidence`` low / ``abstained: true`` → the top hit is
|
|
330
|
-
weak. Re-query with a sharper phrasing, or widen with
|
|
331
|
-
``include_shared=true`` / ``include_global=true`` if appropriate.
|
|
332
|
-
• Confident match → use it directly; no second call needed.
|
|
333
|
-
One extra targeted recall is cheap and beats a wrong "not found".
|
|
334
|
-
|
|
335
|
-
Optional ``session_id`` threads through to the
|
|
336
|
-
engine's outcome-queue so PostToolUse / Stop hooks can attach
|
|
337
|
-
engagement signals to this recall. Claude Code should pass its
|
|
338
|
-
``CLAUDE_SESSION_ID``. Omitting it degrades to "no closed-loop
|
|
339
|
-
learning for this recall" — the recall itself always works.
|
|
340
|
-
|
|
341
|
-
Multi-scope: ``include_global`` / ``include_shared`` control which
|
|
342
|
-
scopes participate in retrieval. Leave them unset (``None``) to use the
|
|
343
|
-
configured default — shared memory is OPT-IN, so by default recall
|
|
344
|
-
returns only this profile's own facts. Pass ``True`` to opt in per call.
|
|
345
|
-
|
|
346
|
-
Time window: optional ``window`` restricts results to a event-time
|
|
347
|
-
range. Accepts a relative span (``"24h"``, ``"7d"``, ``"30d"``,
|
|
348
|
-
``"1y"``) or an explicit range (``"2026-07-01..2026-07-31"``). Empty =
|
|
349
|
-
no time filter.
|
|
350
|
-
|
|
351
|
-
Point-in-time: optional ``as_of`` (ISO-8601 string, e.g.
|
|
352
|
-
``"2026-01-01T00:00:00+00:00"``) pins recall to a temporal snapshot;
|
|
353
|
-
omit or pass ``None`` for current-state recall.
|
|
354
|
-
"""
|
|
355
|
-
# v3.6.10: resolve "mcp_client" sentinel → URL path (HTTP) or env var (stdio)
|
|
356
|
-
if agent_id == "mcp_client":
|
|
357
|
-
from superlocalmemory.mcp.agent_context import get_current_agent_id
|
|
358
|
-
agent_id = get_current_agent_id()
|
|
359
|
-
import asyncio
|
|
360
|
-
try:
|
|
361
|
-
from superlocalmemory.mcp._daemon_proxy import choose_pool
|
|
362
|
-
from superlocalmemory.mcp.session_binding import resolve_session_id
|
|
363
|
-
|
|
364
|
-
# S9-DASH-10's four-step ladder, now shared with remember() so the
|
|
365
|
-
# read path and the write path cannot disagree about which session
|
|
366
|
-
# they are in. remember() had no ladder at all, which is why 95% of
|
|
367
|
-
# stored facts carry no session_id. See mcp/session_binding.py.
|
|
368
|
-
#
|
|
369
|
-
# The per-agent fallback stays ON here: this id settles a pending
|
|
370
|
-
# outcome, and `mcp:<agent_id>` is deliberately not matched by the
|
|
371
|
-
# Stop hook, so the reaper settles it at a neutral 0.5 rather than
|
|
372
|
-
# attributing engagement to a session that never existed.
|
|
373
|
-
effective_sid = resolve_session_id(
|
|
374
|
-
session_id, agent_id=agent_id, allow_agent_fallback=True,
|
|
375
|
-
)
|
|
376
|
-
# Resolve the daemon proxy inside the worker too. ``choose_pool``
|
|
377
|
-
# verifies daemon ownership through a synchronous /health request;
|
|
378
|
-
# when this tool is served by the daemon's mounted HTTP MCP app,
|
|
379
|
-
# resolving it on Uvicorn's event-loop thread makes that loop wait
|
|
380
|
-
# on its own health response forever. Stdio did not exhibit this
|
|
381
|
-
# because its MCP process is external to the daemon.
|
|
382
|
-
#
|
|
383
|
-
# V3.4.26: WorkerPool now concurrent — parallel calls no longer
|
|
384
|
-
# block behind a single threading.Lock. See worker_pool.py.
|
|
385
|
-
# Phase 4b: normalize as_of at MCP boundary. Invalid → reject.
|
|
386
|
-
# Audit P2: treat empty/whitespace as_of as ABSENT (like HTTP does),
|
|
387
|
-
# not as an invalid value — only a non-blank unparseable string is
|
|
388
|
-
# rejected.
|
|
389
|
-
def _normalize_temporal(value: str | None) -> str | None:
|
|
390
|
-
if value is None or not str(value).strip():
|
|
391
|
-
return None
|
|
392
|
-
from superlocalmemory.retrieval.temporal_utils import normalize_as_of
|
|
393
|
-
return normalize_as_of(value)
|
|
394
|
-
|
|
395
|
-
raw_as_of, raw_known_as_of, raw_valid_at = as_of, known_as_of, valid_at
|
|
396
|
-
as_of = _normalize_temporal(raw_as_of)
|
|
397
|
-
known_as_of = _normalize_temporal(raw_known_as_of)
|
|
398
|
-
valid_at = _normalize_temporal(raw_valid_at)
|
|
399
|
-
# Preserve backwards-compatible as_of validation while exposing
|
|
400
|
-
# named two-clock boundaries. A supplied non-blank invalid value
|
|
401
|
-
# is rejected rather than silently becoming current recall.
|
|
402
|
-
for raw, normalized, code in (
|
|
403
|
-
(raw_as_of, as_of, "invalid_as_of"),
|
|
404
|
-
(raw_known_as_of, known_as_of, "invalid_known_as_of"),
|
|
405
|
-
(raw_valid_at, valid_at, "invalid_valid_at"),
|
|
406
|
-
):
|
|
407
|
-
if raw is not None and str(raw).strip() and normalized is None:
|
|
408
|
-
return {"success": False, "error": code}
|
|
409
|
-
|
|
410
|
-
from superlocalmemory.core.admission import enforce_read_scope
|
|
411
|
-
_incl_global, _incl_shared = enforce_read_scope(include_global, include_shared)
|
|
412
|
-
|
|
413
|
-
def _recall_via_daemon_pool():
|
|
414
|
-
pool = choose_pool()
|
|
415
|
-
return pool.recall(
|
|
416
|
-
query, limit=limit, session_id=effective_sid,
|
|
417
|
-
fast=fast, include_global=_incl_global,
|
|
418
|
-
include_shared=_incl_shared, window=window or None,
|
|
419
|
-
as_of=as_of,
|
|
420
|
-
known_as_of=known_as_of,
|
|
421
|
-
valid_at=valid_at,
|
|
422
|
-
include_unknown=include_unknown,
|
|
423
|
-
)
|
|
424
|
-
|
|
425
|
-
result = await asyncio.to_thread(
|
|
426
|
-
_recall_via_daemon_pool,
|
|
427
|
-
)
|
|
428
|
-
if result.get("ok"):
|
|
429
|
-
return {
|
|
430
|
-
"success": True,
|
|
431
|
-
"results": result.get("results", []),
|
|
432
|
-
"count": result.get("result_count", 0),
|
|
433
|
-
"query_type": result.get("query_type", "unknown"),
|
|
434
|
-
"channel_weights": result.get("channel_weights", {}),
|
|
435
|
-
"retrieval_time_ms": result.get("retrieval_time_ms", 0),
|
|
436
|
-
# v3.6.6: surface evidence-floor signal to MCP clients.
|
|
437
|
-
"no_confident_match": result.get("no_confident_match", False),
|
|
438
|
-
"score_contract_version": result.get("score_contract_version", "2"),
|
|
439
|
-
"calibration_status": result.get("calibration_status", "uncalibrated"),
|
|
440
|
-
"calibration_id": result.get("calibration_id"),
|
|
441
|
-
# Quote this back to report_outcome and the report ties to
|
|
442
|
-
# this exact answer instead of being matched by guesswork.
|
|
443
|
-
"query_id": result.get("query_id", ""),
|
|
444
|
-
"answer_confidence": result.get("answer_confidence"),
|
|
445
|
-
"abstained": result.get("abstained", False),
|
|
446
|
-
"abstention_reason": result.get("abstention_reason"),
|
|
447
|
-
}
|
|
448
|
-
return {"success": False, "error": result.get("error", "Recall failed")}
|
|
449
|
-
except Exception as exc:
|
|
450
|
-
logger.exception("recall failed")
|
|
451
|
-
return {"success": False, "error": str(exc)}
|
|
452
|
-
|
|
453
|
-
@server.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
454
|
-
@admits(OperationKind.RECALL)
|
|
455
|
-
async def search(query: str, limit: int = CANONICAL_RECALL_LIMIT) -> dict:
|
|
456
|
-
"""Full-text search across memories using FTS5 with BM25 ranking."""
|
|
457
|
-
try:
|
|
458
|
-
engine = get_engine()
|
|
459
|
-
pid = await _runtime_profile(get_engine)
|
|
460
|
-
facts = engine._db.search_facts_fts(query, pid, limit=limit)
|
|
461
|
-
items = []
|
|
462
|
-
for f in facts:
|
|
463
|
-
items.append({
|
|
464
|
-
"fact_id": f.fact_id,
|
|
465
|
-
"content": f.content,
|
|
466
|
-
"fact_type": f.fact_type.value,
|
|
467
|
-
"confidence": round(f.confidence, 3),
|
|
468
|
-
"date": f.observation_date,
|
|
469
|
-
})
|
|
470
|
-
return {"success": True, "results": items, "count": len(items)}
|
|
471
|
-
except Exception as exc:
|
|
472
|
-
logger.exception("search failed")
|
|
473
|
-
return {"success": False, "error": str(exc)}
|
|
474
|
-
|
|
475
|
-
@server.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
476
|
-
@admits(OperationKind.RECALL)
|
|
477
|
-
async def fetch(fact_ids: str) -> dict:
|
|
478
|
-
"""Fetch full details for specific fact IDs (comma-separated)."""
|
|
479
|
-
try:
|
|
480
|
-
engine = get_engine()
|
|
481
|
-
ids = [fid.strip() for fid in fact_ids.split(",") if fid.strip()]
|
|
482
|
-
pid = await _runtime_profile(get_engine)
|
|
483
|
-
facts = engine._db.get_facts_by_ids(ids, pid)
|
|
484
|
-
items = []
|
|
485
|
-
for f in facts:
|
|
486
|
-
items.append({
|
|
487
|
-
"fact_id": f.fact_id,
|
|
488
|
-
"content": f.content,
|
|
489
|
-
"fact_type": f.fact_type.value,
|
|
490
|
-
"entities": f.canonical_entities,
|
|
491
|
-
"confidence": round(f.confidence, 3),
|
|
492
|
-
"importance": round(f.importance, 3),
|
|
493
|
-
"observation_date": f.observation_date,
|
|
494
|
-
"referenced_date": f.referenced_date,
|
|
495
|
-
"lifecycle": f.lifecycle.value,
|
|
496
|
-
"access_count": f.access_count,
|
|
497
|
-
})
|
|
498
|
-
return {"success": True, "results": items, "count": len(items)}
|
|
499
|
-
except Exception as exc:
|
|
500
|
-
logger.exception("fetch failed")
|
|
501
|
-
return {"success": False, "error": str(exc)}
|
|
502
|
-
|
|
503
|
-
@server.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
504
|
-
@admits(OperationKind.RECALL)
|
|
505
|
-
async def list_recent(limit: int = CANONICAL_LIST_LIMIT) -> dict:
|
|
506
|
-
"""List most recently stored memories, newest first."""
|
|
507
|
-
try:
|
|
508
|
-
engine = get_engine()
|
|
509
|
-
pid = await _runtime_profile(get_engine)
|
|
510
|
-
# v3.6.12 (search-2): push the limit into the query — was loading the
|
|
511
|
-
# ENTIRE facts table (deserializing every 768-float embedding) just
|
|
512
|
-
# to return the top N. get_all_facts preserves created_at DESC order.
|
|
513
|
-
facts = engine._db.get_all_facts(pid, limit=limit)
|
|
514
|
-
items = []
|
|
515
|
-
for f in facts:
|
|
516
|
-
items.append({
|
|
517
|
-
"fact_id": f.fact_id,
|
|
518
|
-
"content": f.content[:120],
|
|
519
|
-
"fact_type": f.fact_type.value,
|
|
520
|
-
"created_at": f.created_at,
|
|
521
|
-
"session_id": f.session_id,
|
|
522
|
-
})
|
|
523
|
-
return {"success": True, "results": items, "count": len(items)}
|
|
524
|
-
except Exception as exc:
|
|
525
|
-
logger.exception("list_recent failed")
|
|
526
|
-
return {"success": False, "error": str(exc)}
|
|
527
|
-
|
|
528
|
-
@server.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
529
|
-
async def get_status() -> dict:
|
|
530
|
-
"""Get memory system status: fact count, entity count, mode, profile, db size."""
|
|
531
|
-
try:
|
|
532
|
-
# Same source the HTTP surface reads, imported here rather than at
|
|
533
|
-
# module scope: that module costs ~260ms and MCP starts over stdio.
|
|
534
|
-
from superlocalmemory.server.routes.helpers import SLM_VERSION
|
|
535
|
-
|
|
536
|
-
import asyncio
|
|
537
|
-
import os
|
|
538
|
-
|
|
539
|
-
from superlocalmemory.cli.daemon import (
|
|
540
|
-
daemon_request,
|
|
541
|
-
is_daemon_running,
|
|
542
|
-
)
|
|
543
|
-
|
|
544
|
-
if await asyncio.to_thread(is_daemon_running):
|
|
545
|
-
daemon_status = await asyncio.to_thread(
|
|
546
|
-
daemon_request,
|
|
547
|
-
"GET",
|
|
548
|
-
"/status",
|
|
549
|
-
)
|
|
550
|
-
if isinstance(daemon_status, dict) and daemon_status.get("profile"):
|
|
551
|
-
return {
|
|
552
|
-
"success": True,
|
|
553
|
-
"mode": daemon_status.get("mode", "unknown"),
|
|
554
|
-
"provider": daemon_status.get("provider", "none"),
|
|
555
|
-
"profile": daemon_status["profile"],
|
|
556
|
-
"base_dir": daemon_status.get("base_dir", ""),
|
|
557
|
-
"db_path": daemon_status.get("db_path", ""),
|
|
558
|
-
"db_size_mb": float(daemon_status.get("db_size_mb", 0.0)),
|
|
559
|
-
"fact_count": int(daemon_status.get("fact_count", 0)),
|
|
560
|
-
"entity_count": int(daemon_status.get("entity_count", 0)),
|
|
561
|
-
"edge_count": int(daemon_status.get("edge_count", 0)),
|
|
562
|
-
"profile_generation": int(
|
|
563
|
-
daemon_status.get("profile_generation", 0)
|
|
564
|
-
),
|
|
565
|
-
"version": SLM_VERSION,
|
|
566
|
-
"projection_queue_depth": int(
|
|
567
|
-
daemon_status.get("projection_queue_depth", 0)
|
|
568
|
-
),
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
engine = get_engine()
|
|
572
|
-
pid = engine.profile_id
|
|
573
|
-
fact_count = engine._db.get_fact_count(pid)
|
|
574
|
-
entities = engine._db.execute(
|
|
575
|
-
"SELECT COUNT(*) AS c FROM canonical_entities WHERE profile_id = ?",
|
|
576
|
-
(pid,),
|
|
577
|
-
)
|
|
578
|
-
entity_count = int(dict(entities[0])["c"]) if entities else 0
|
|
579
|
-
edges = engine._db.execute(
|
|
580
|
-
"SELECT COUNT(*) AS c FROM graph_edges WHERE profile_id = ?",
|
|
581
|
-
(pid,),
|
|
582
|
-
)
|
|
583
|
-
edge_count = int(dict(edges[0])["c"]) if edges else 0
|
|
584
|
-
|
|
585
|
-
db_size_mb = 0.0
|
|
586
|
-
db_path = engine._db.db_path
|
|
587
|
-
if db_path.exists():
|
|
588
|
-
db_size_mb = round(os.path.getsize(db_path) / (1024 * 1024), 2)
|
|
589
|
-
|
|
590
|
-
# additive canonical key set — provider/base_dir/db_path added.
|
|
591
|
-
# All pre-existing keys are preserved (zero removals).
|
|
592
|
-
cfg = engine._config
|
|
593
|
-
return {
|
|
594
|
-
"success": True,
|
|
595
|
-
"mode": cfg.mode.value,
|
|
596
|
-
"provider": cfg.llm.provider or "none",
|
|
597
|
-
"profile": pid,
|
|
598
|
-
"base_dir": str(cfg.base_dir),
|
|
599
|
-
"db_path": str(db_path),
|
|
600
|
-
"db_size_mb": db_size_mb,
|
|
601
|
-
"fact_count": fact_count,
|
|
602
|
-
"entity_count": entity_count,
|
|
603
|
-
"edge_count": edge_count,
|
|
604
|
-
"profile_generation": 0,
|
|
605
|
-
"version": SLM_VERSION,
|
|
606
|
-
"projection_queue_depth": _projection_queue_depth(engine._db),
|
|
607
|
-
}
|
|
608
|
-
except Exception as exc:
|
|
609
|
-
logger.exception("get_status failed")
|
|
610
|
-
return {"success": False, "error": str(exc)}
|
|
611
|
-
|
|
612
|
-
@server.tool()
|
|
613
|
-
@admits(OperationKind.CORRECT)
|
|
614
|
-
async def build_graph() -> dict:
|
|
615
|
-
"""Rebuild knowledge graph edges for all facts in the active profile."""
|
|
616
|
-
try:
|
|
617
|
-
engine = get_engine()
|
|
618
|
-
pid = await _runtime_profile(get_engine)
|
|
619
|
-
authorization = authorize_mcp_mutation(
|
|
620
|
-
engine,
|
|
621
|
-
"update",
|
|
622
|
-
mutation_source="mcp-build-memory-graph",
|
|
623
|
-
profile_id=pid,
|
|
624
|
-
)
|
|
625
|
-
facts = engine._db.get_all_facts(pid)
|
|
626
|
-
edge_count = 0
|
|
627
|
-
for fact in facts:
|
|
628
|
-
if engine._graph_builder:
|
|
629
|
-
engine._graph_builder.build_edges(fact, pid)
|
|
630
|
-
edge_count += 1
|
|
631
|
-
authorization.complete()
|
|
632
|
-
return {
|
|
633
|
-
"success": True,
|
|
634
|
-
"facts_processed": len(facts),
|
|
635
|
-
"edges_built": edge_count,
|
|
636
|
-
}
|
|
637
|
-
except Exception as exc:
|
|
638
|
-
logger.exception("build_graph failed")
|
|
639
|
-
return {"success": False, "error": str(exc)}
|
|
640
|
-
|
|
641
|
-
@server.tool()
|
|
642
|
-
@admits(OperationKind.PROFILE_SWITCH)
|
|
643
|
-
async def switch_profile(profile_id: str) -> dict:
|
|
644
|
-
"""Switch the active memory profile. All operations scope to this profile."""
|
|
645
|
-
try:
|
|
646
|
-
import asyncio
|
|
647
|
-
|
|
648
|
-
engine = get_engine()
|
|
649
|
-
old = engine.profile_id
|
|
650
|
-
authorization = authorize_mcp_mutation(
|
|
651
|
-
engine,
|
|
652
|
-
"update",
|
|
653
|
-
mutation_source="mcp-switch-profile",
|
|
654
|
-
profile_id=profile_id,
|
|
655
|
-
content_preview=f"{old} -> {profile_id}",
|
|
656
|
-
)
|
|
657
|
-
from superlocalmemory.cli.daemon import (
|
|
658
|
-
daemon_request,
|
|
659
|
-
is_daemon_running,
|
|
660
|
-
)
|
|
661
|
-
|
|
662
|
-
generation = 0
|
|
663
|
-
# Only the profile_id explicitly confirmed by this process
|
|
664
|
-
# (daemon-acknowledged + locally-validated, or locally
|
|
665
|
-
# validated directly) is ever synced into engine state.
|
|
666
|
-
confirmed_profile_id = None
|
|
667
|
-
if await asyncio.to_thread(is_daemon_running):
|
|
668
|
-
result = await asyncio.to_thread(
|
|
669
|
-
daemon_request,
|
|
670
|
-
"POST",
|
|
671
|
-
f"/api/profiles/{profile_id}/switch",
|
|
672
|
-
)
|
|
673
|
-
if not result or not result.get("success"):
|
|
674
|
-
return {
|
|
675
|
-
"success": False,
|
|
676
|
-
"error": "resident daemon rejected the profile switch",
|
|
677
|
-
}
|
|
678
|
-
acknowledged = str(result.get("active_profile", ""))
|
|
679
|
-
if not acknowledged or acknowledged != profile_id:
|
|
680
|
-
return {
|
|
681
|
-
"success": False,
|
|
682
|
-
"error": "resident daemon acknowledged a different profile",
|
|
683
|
-
}
|
|
684
|
-
# Local consistency guard (SEC-H-01): the daemon's HTTP
|
|
685
|
-
# acknowledgement alone is not sufficient — this MCP
|
|
686
|
-
# process must also confirm the profile exists in its
|
|
687
|
-
# own local DB handle before syncing local state to it.
|
|
688
|
-
# Mirrors the existence check the no-daemon branch already
|
|
689
|
-
# performs below.
|
|
690
|
-
local_rows = engine._db.execute(
|
|
691
|
-
"SELECT 1 FROM profiles WHERE profile_id = ?",
|
|
692
|
-
(profile_id,),
|
|
693
|
-
)
|
|
694
|
-
if not local_rows:
|
|
695
|
-
return {
|
|
696
|
-
"success": False,
|
|
697
|
-
"error": (
|
|
698
|
-
f"resident daemon acknowledged profile "
|
|
699
|
-
f"'{acknowledged}' but it does not exist in "
|
|
700
|
-
f"this process's local profile store"
|
|
701
|
-
),
|
|
702
|
-
}
|
|
703
|
-
generation = int(result.get("generation", 0))
|
|
704
|
-
# Sync target is the DAEMON-CONFIRMED value, never the raw
|
|
705
|
-
# caller-supplied profile_id, even though they are equal
|
|
706
|
-
# here by construction (checked above).
|
|
707
|
-
confirmed_profile_id = acknowledged
|
|
708
|
-
else:
|
|
709
|
-
rows = engine._db.execute(
|
|
710
|
-
"SELECT 1 FROM profiles WHERE profile_id = ?",
|
|
711
|
-
(profile_id,),
|
|
712
|
-
)
|
|
713
|
-
if not rows:
|
|
714
|
-
return {
|
|
715
|
-
"success": False,
|
|
716
|
-
"error": f"Profile '{profile_id}' does not exist.",
|
|
717
|
-
}
|
|
718
|
-
from superlocalmemory.server.profile_runtime import (
|
|
719
|
-
persist_active_profile,
|
|
720
|
-
)
|
|
721
|
-
|
|
722
|
-
persistence = persist_active_profile(profile_id)
|
|
723
|
-
try:
|
|
724
|
-
engine.profile_id = profile_id
|
|
725
|
-
engine._config.active_profile = profile_id
|
|
726
|
-
except BaseException:
|
|
727
|
-
engine.profile_id = old
|
|
728
|
-
engine._config.active_profile = old
|
|
729
|
-
persistence.rollback()
|
|
730
|
-
raise
|
|
731
|
-
confirmed_profile_id = profile_id
|
|
732
|
-
|
|
733
|
-
if not confirmed_profile_id:
|
|
734
|
-
# Defensive: should be unreachable — every path above
|
|
735
|
-
# either returns an error or sets confirmed_profile_id.
|
|
736
|
-
return {
|
|
737
|
-
"success": False,
|
|
738
|
-
"error": "profile switch could not be confirmed",
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
# Synchronize this MCP process only after confirmation
|
|
742
|
-
# (daemon-acknowledged + locally-validated, or directly
|
|
743
|
-
# locally-validated in the no-daemon branch above).
|
|
744
|
-
engine.profile_id = confirmed_profile_id
|
|
745
|
-
engine._config.active_profile = confirmed_profile_id
|
|
746
|
-
|
|
747
|
-
# v3.6.12 (search-3): recall/delete run in a separate worker
|
|
748
|
-
# subprocess that caches its engine (and profile_id) at init. Recycle
|
|
749
|
-
# it so the NEXT recall uses the new profile instead of the stale one.
|
|
750
|
-
try:
|
|
751
|
-
from superlocalmemory.core.worker_pool import WorkerPool
|
|
752
|
-
WorkerPool.shared().shutdown()
|
|
753
|
-
except Exception:
|
|
754
|
-
logger.debug("worker-pool recycle on profile switch skipped")
|
|
755
|
-
|
|
756
|
-
authorization.complete()
|
|
757
|
-
return {
|
|
758
|
-
"success": True,
|
|
759
|
-
"previous_profile": old,
|
|
760
|
-
"current_profile": profile_id,
|
|
761
|
-
"generation": generation,
|
|
762
|
-
}
|
|
763
|
-
except Exception as exc:
|
|
764
|
-
logger.exception("switch_profile failed")
|
|
765
|
-
return {"success": False, "error": str(exc)}
|
|
766
|
-
|
|
767
|
-
@server.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
768
|
-
async def backup_status() -> dict:
|
|
769
|
-
"""Get backup system status, last backup time, and available backup files."""
|
|
770
|
-
try:
|
|
771
|
-
engine = get_engine()
|
|
772
|
-
from superlocalmemory.infra.backup import BackupManager
|
|
773
|
-
bm = BackupManager(
|
|
774
|
-
db_path=engine._db.db_path,
|
|
775
|
-
base_dir=engine._config.base_dir,
|
|
776
|
-
)
|
|
777
|
-
return {"success": True, **bm.get_status()}
|
|
778
|
-
except Exception as exc:
|
|
779
|
-
logger.exception("backup_status failed")
|
|
780
|
-
return {"success": False, "error": str(exc)}
|
|
781
|
-
|
|
782
|
-
@server.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
783
|
-
async def memory_used() -> dict:
|
|
784
|
-
"""Get memory usage breakdown by fact type and lifecycle state."""
|
|
785
|
-
try:
|
|
786
|
-
engine = get_engine()
|
|
787
|
-
pid = await _runtime_profile(get_engine)
|
|
788
|
-
facts = engine._db.get_all_facts(pid)
|
|
789
|
-
by_type: dict[str, int] = {}
|
|
790
|
-
by_lifecycle: dict[str, int] = {}
|
|
791
|
-
for f in facts:
|
|
792
|
-
by_type[f.fact_type.value] = by_type.get(f.fact_type.value, 0) + 1
|
|
793
|
-
by_lifecycle[f.lifecycle.value] = (
|
|
794
|
-
by_lifecycle.get(f.lifecycle.value, 0) + 1
|
|
795
|
-
)
|
|
796
|
-
return {
|
|
797
|
-
"success": True,
|
|
798
|
-
"total_facts": len(facts),
|
|
799
|
-
"by_type": by_type,
|
|
800
|
-
"by_lifecycle": by_lifecycle,
|
|
801
|
-
"profile": pid,
|
|
802
|
-
}
|
|
803
|
-
except Exception as exc:
|
|
804
|
-
logger.exception("memory_used failed")
|
|
805
|
-
return {"success": False, "error": str(exc)}
|
|
806
|
-
|
|
807
|
-
@server.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
808
|
-
async def get_learned_patterns(pattern_type: str = "", limit: int = 20) -> dict:
|
|
809
|
-
"""Get learned behavioral patterns (interests, refinements, archival habits)."""
|
|
810
|
-
try:
|
|
811
|
-
engine = get_engine()
|
|
812
|
-
pid = await _runtime_profile(get_engine)
|
|
813
|
-
from superlocalmemory.learning.behavioral import BehavioralPatternStore
|
|
814
|
-
store = BehavioralPatternStore(engine._db.db_path)
|
|
815
|
-
ptype = pattern_type if pattern_type else None
|
|
816
|
-
patterns = store.get_patterns(
|
|
817
|
-
pid, pattern_type=ptype, limit=limit,
|
|
818
|
-
)
|
|
819
|
-
return {"success": True, "patterns": patterns, "count": len(patterns)}
|
|
820
|
-
except Exception as exc:
|
|
821
|
-
logger.exception("get_learned_patterns failed")
|
|
822
|
-
return {"success": False, "error": str(exc)}
|
|
823
|
-
|
|
824
|
-
@server.tool()
|
|
825
|
-
@admits(OperationKind.CORRECT)
|
|
826
|
-
async def correct_pattern(pattern_id: str, correction: str) -> dict:
|
|
827
|
-
"""Correct or annotate a learned behavioral pattern to improve retrieval."""
|
|
828
|
-
try:
|
|
829
|
-
engine = get_engine()
|
|
830
|
-
pid = await _runtime_profile(get_engine)
|
|
831
|
-
authorization = authorize_mcp_mutation(
|
|
832
|
-
engine,
|
|
833
|
-
"update",
|
|
834
|
-
mutation_source="mcp-correct-pattern",
|
|
835
|
-
profile_id=pid,
|
|
836
|
-
fact_id=pattern_id,
|
|
837
|
-
content_preview=correction,
|
|
838
|
-
)
|
|
839
|
-
from superlocalmemory.learning.behavioral import BehavioralPatternStore
|
|
840
|
-
store = BehavioralPatternStore(engine._db.db_path)
|
|
841
|
-
store.record(
|
|
842
|
-
pid,
|
|
843
|
-
pattern_type="correction",
|
|
844
|
-
pattern_key=pattern_id,
|
|
845
|
-
metadata={"correction": correction},
|
|
846
|
-
)
|
|
847
|
-
authorization.complete()
|
|
848
|
-
return {"success": True, "pattern_id": pattern_id}
|
|
849
|
-
except Exception as exc:
|
|
850
|
-
logger.exception("correct_pattern failed")
|
|
851
|
-
return {"success": False, "error": str(exc)}
|
|
852
|
-
|
|
853
|
-
@server.tool(annotations=ToolAnnotations(destructiveHint=True))
|
|
854
|
-
@admits(OperationKind.FORGET)
|
|
855
|
-
async def delete_memory(fact_id: str, agent_id: str = "mcp_client") -> dict:
|
|
856
|
-
"""Delete a specific memory by exact fact ID.
|
|
857
|
-
|
|
858
|
-
Security note: This is a destructive operation. All deletions are
|
|
859
|
-
logged with the calling agent_id for audit trail. Use get_status or
|
|
860
|
-
list_recent to find fact_ids before deleting.
|
|
861
|
-
|
|
862
|
-
Args:
|
|
863
|
-
fact_id: Exact fact ID to delete (from recall or list_recent results).
|
|
864
|
-
agent_id: Identifier of the calling agent (logged for audit).
|
|
865
|
-
"""
|
|
866
|
-
# v3.6.10: resolve "mcp_client" sentinel → URL path (HTTP) or env var (stdio)
|
|
867
|
-
if agent_id == "mcp_client":
|
|
868
|
-
from superlocalmemory.mcp.agent_context import get_current_agent_id
|
|
869
|
-
agent_id = get_current_agent_id()
|
|
870
|
-
try:
|
|
871
|
-
import asyncio
|
|
872
|
-
import urllib.parse
|
|
873
|
-
|
|
874
|
-
from superlocalmemory.cli.daemon import (
|
|
875
|
-
daemon_request,
|
|
876
|
-
is_daemon_running,
|
|
877
|
-
)
|
|
878
|
-
|
|
879
|
-
if await asyncio.to_thread(is_daemon_running):
|
|
880
|
-
path = "/api/memories/" + urllib.parse.quote(fact_id, safe="")
|
|
881
|
-
result = await asyncio.to_thread(
|
|
882
|
-
daemon_request, "DELETE", path,
|
|
883
|
-
)
|
|
884
|
-
if isinstance(result, dict) and result.get("success"):
|
|
885
|
-
_emit_event("memory.deleted", {
|
|
886
|
-
"fact_id": fact_id,
|
|
887
|
-
"agent_id": agent_id,
|
|
888
|
-
}, source_agent=agent_id)
|
|
889
|
-
return {
|
|
890
|
-
"success": True, "deleted": fact_id,
|
|
891
|
-
"agent_id": agent_id,
|
|
892
|
-
}
|
|
893
|
-
return {
|
|
894
|
-
"success": False,
|
|
895
|
-
"retryable": True,
|
|
896
|
-
"error": "resident daemon rejected the delete operation",
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
from superlocalmemory.core.worker_pool import WorkerPool
|
|
900
|
-
pool = WorkerPool.shared()
|
|
901
|
-
result = pool._send({
|
|
902
|
-
"cmd": "delete_memory",
|
|
903
|
-
"fact_id": fact_id,
|
|
904
|
-
# Informational IDE/client label only. The worker derives its
|
|
905
|
-
# authorization actor from the private local capability.
|
|
906
|
-
"source_agent_id": agent_id,
|
|
907
|
-
})
|
|
908
|
-
if result.get("ok"):
|
|
909
|
-
logger.info("Memory deleted: %s by agent: %s", fact_id[:16], agent_id)
|
|
910
|
-
_emit_event("memory.deleted", {
|
|
911
|
-
"fact_id": fact_id,
|
|
912
|
-
"agent_id": agent_id,
|
|
913
|
-
}, source_agent=agent_id)
|
|
914
|
-
return {"success": True, "deleted": fact_id, "agent_id": agent_id}
|
|
915
|
-
return {"success": False, "error": result.get("error", "Delete failed")}
|
|
916
|
-
except Exception as exc:
|
|
917
|
-
logger.exception("delete_memory failed")
|
|
918
|
-
return {"success": False, "error": str(exc)}
|
|
919
|
-
|
|
920
|
-
@server.tool(annotations=ToolAnnotations(idempotentHint=True))
|
|
921
|
-
@admits(OperationKind.CORRECT)
|
|
922
|
-
async def update_memory(
|
|
923
|
-
fact_id: str, content: str, agent_id: str = "mcp_client",
|
|
924
|
-
) -> dict:
|
|
925
|
-
"""Update the content of a specific memory by exact fact ID.
|
|
926
|
-
|
|
927
|
-
Security note: All updates are logged with the calling agent_id.
|
|
928
|
-
The fact_id must belong to the active profile.
|
|
929
|
-
|
|
930
|
-
Args:
|
|
931
|
-
fact_id: Exact fact ID to update.
|
|
932
|
-
content: New content for the memory (cannot be empty).
|
|
933
|
-
agent_id: Identifier of the calling agent (logged for audit).
|
|
934
|
-
"""
|
|
935
|
-
# v3.6.10: resolve "mcp_client" sentinel → URL path (HTTP) or env var (stdio)
|
|
936
|
-
if agent_id == "mcp_client":
|
|
937
|
-
from superlocalmemory.mcp.agent_context import get_current_agent_id
|
|
938
|
-
agent_id = get_current_agent_id()
|
|
939
|
-
try:
|
|
940
|
-
if not content or not content.strip():
|
|
941
|
-
return {"success": False, "error": "content cannot be empty"}
|
|
942
|
-
import asyncio
|
|
943
|
-
import urllib.parse
|
|
944
|
-
|
|
945
|
-
from superlocalmemory.cli.daemon import (
|
|
946
|
-
daemon_request,
|
|
947
|
-
is_daemon_running,
|
|
948
|
-
)
|
|
949
|
-
|
|
950
|
-
if await asyncio.to_thread(is_daemon_running):
|
|
951
|
-
path = "/api/memories/" + urllib.parse.quote(fact_id, safe="")
|
|
952
|
-
result = await asyncio.to_thread(
|
|
953
|
-
daemon_request,
|
|
954
|
-
"PATCH",
|
|
955
|
-
path,
|
|
956
|
-
{"content": content.strip()},
|
|
957
|
-
)
|
|
958
|
-
if isinstance(result, dict) and result.get("success"):
|
|
959
|
-
return {
|
|
960
|
-
"success": True,
|
|
961
|
-
"predecessor_fact_id": result.get("predecessor_fact_id", fact_id),
|
|
962
|
-
"successor_fact_id": result.get("successor_fact_id"),
|
|
963
|
-
"correction_case": result.get("correction_case"),
|
|
964
|
-
"review_required": bool(result.get("review_required", False)),
|
|
965
|
-
}
|
|
966
|
-
return {
|
|
967
|
-
"success": False,
|
|
968
|
-
"retryable": True,
|
|
969
|
-
"error": "resident daemon rejected the update operation",
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
from superlocalmemory.core.worker_pool import WorkerPool
|
|
973
|
-
pool = WorkerPool.shared()
|
|
974
|
-
result = pool._send({
|
|
975
|
-
"cmd": "update_memory",
|
|
976
|
-
"fact_id": fact_id,
|
|
977
|
-
"content": content.strip(),
|
|
978
|
-
"source_agent_id": agent_id,
|
|
979
|
-
})
|
|
980
|
-
if result.get("ok"):
|
|
981
|
-
logger.info("Memory updated: %s by agent: %s", fact_id[:16], agent_id)
|
|
982
|
-
return {
|
|
983
|
-
"success": True,
|
|
984
|
-
"predecessor_fact_id": result.get("predecessor_fact_id", fact_id),
|
|
985
|
-
"successor_fact_id": result.get("successor_fact_id"),
|
|
986
|
-
"correction_case": result.get("correction_case"),
|
|
987
|
-
"review_required": bool(result.get("review_required", False)),
|
|
988
|
-
}
|
|
989
|
-
return {"success": False, "error": result.get("error", "Update failed")}
|
|
990
|
-
except Exception as exc:
|
|
991
|
-
logger.exception("update_memory failed")
|
|
992
|
-
return {"success": False, "error": str(exc)}
|
|
993
|
-
|
|
994
|
-
@server.tool(annotations=ToolAnnotations(idempotentHint=True))
|
|
995
|
-
@admits(OperationKind.CORRECT)
|
|
996
|
-
async def review_correction(
|
|
997
|
-
case_id: str,
|
|
998
|
-
action: str,
|
|
999
|
-
expected_version: int,
|
|
1000
|
-
event_valid_until: str | None = None,
|
|
1001
|
-
) -> dict:
|
|
1002
|
-
"""Apply, reject, or roll back a review-gated correction case.
|
|
1003
|
-
|
|
1004
|
-
The active daemon derives reviewer identity and profile from its local
|
|
1005
|
-
authenticated MCP boundary. Clients provide only a case address, a
|
|
1006
|
-
CAS version, and an optional reviewer-approved event-time boundary.
|
|
1007
|
-
"""
|
|
1008
|
-
if action not in {"apply", "reject", "rollback"}:
|
|
1009
|
-
return {"success": False, "error": "action must be apply, reject, or rollback"}
|
|
1010
|
-
if not isinstance(expected_version, int) or isinstance(expected_version, bool):
|
|
1011
|
-
return {"success": False, "error": "expected_version must be an integer"}
|
|
1012
|
-
if expected_version < 0:
|
|
1013
|
-
return {"success": False, "error": "expected_version must be non-negative"}
|
|
1014
|
-
try:
|
|
1015
|
-
import asyncio
|
|
1016
|
-
import urllib.parse
|
|
1017
|
-
|
|
1018
|
-
from superlocalmemory.cli.daemon import daemon_request, is_daemon_running
|
|
1019
|
-
|
|
1020
|
-
if not await asyncio.to_thread(is_daemon_running):
|
|
1021
|
-
return {
|
|
1022
|
-
"success": False,
|
|
1023
|
-
"retryable": True,
|
|
1024
|
-
"error": "correction review requires the resident canonical daemon",
|
|
1025
|
-
}
|
|
1026
|
-
payload: dict[str, object] = {"expected_version": expected_version}
|
|
1027
|
-
if event_valid_until is not None:
|
|
1028
|
-
payload["event_valid_until"] = event_valid_until
|
|
1029
|
-
path = "/api/corrections/" + urllib.parse.quote(case_id, safe="") + "/" + action
|
|
1030
|
-
result = await asyncio.to_thread(daemon_request, "POST", path, payload)
|
|
1031
|
-
if isinstance(result, dict) and result.get("success"):
|
|
1032
|
-
return result
|
|
1033
|
-
return {
|
|
1034
|
-
"success": False,
|
|
1035
|
-
"retryable": True,
|
|
1036
|
-
"error": "resident daemon rejected the correction review",
|
|
1037
|
-
}
|
|
1038
|
-
except Exception:
|
|
1039
|
-
logger.exception("review_correction failed")
|
|
1040
|
-
return {"success": False, "retryable": True, "error": "correction review unavailable"}
|
|
1041
|
-
|
|
1042
|
-
@server.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
1043
|
-
async def list_corrections(limit: int = 100) -> dict:
|
|
1044
|
-
"""List active-profile correction cases for a human or host reviewer."""
|
|
1045
|
-
if not isinstance(limit, int) or isinstance(limit, bool) or not 1 <= limit <= 500:
|
|
1046
|
-
return {"success": False, "error": "limit must be an integer from 1 to 500"}
|
|
1047
|
-
try:
|
|
1048
|
-
import asyncio
|
|
1049
|
-
|
|
1050
|
-
from superlocalmemory.cli.daemon import daemon_request, is_daemon_running
|
|
1051
|
-
|
|
1052
|
-
if not await asyncio.to_thread(is_daemon_running):
|
|
1053
|
-
return {
|
|
1054
|
-
"success": False,
|
|
1055
|
-
"retryable": True,
|
|
1056
|
-
"error": "correction review requires the resident canonical daemon",
|
|
1057
|
-
}
|
|
1058
|
-
result = await asyncio.to_thread(daemon_request, "GET", f"/api/corrections?limit={limit}")
|
|
1059
|
-
if isinstance(result, dict) and result.get("success"):
|
|
1060
|
-
return result
|
|
1061
|
-
return {
|
|
1062
|
-
"success": False,
|
|
1063
|
-
"retryable": True,
|
|
1064
|
-
"error": "resident daemon rejected correction listing",
|
|
1065
|
-
}
|
|
1066
|
-
except Exception:
|
|
1067
|
-
logger.exception("list_corrections failed")
|
|
1068
|
-
return {"success": False, "retryable": True, "error": "correction listing unavailable"}
|
|
1069
|
-
|
|
1070
|
-
@server.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
1071
|
-
async def get_attribution() -> dict:
|
|
1072
|
-
"""Get system attribution: author, version, license, and provenance metadata."""
|
|
1073
|
-
return {
|
|
1074
|
-
"success": True,
|
|
1075
|
-
"product": "SuperLocalMemory V4",
|
|
1076
|
-
"author": "Varun Pratap Bhardwaj",
|
|
1077
|
-
"organization": "Qualixar",
|
|
1078
|
-
"license": "AGPL-3.0-or-later",
|
|
1079
|
-
"urls": {
|
|
1080
|
-
"product": "https://superlocalmemory.com",
|
|
1081
|
-
"author": "https://varunpratap.com",
|
|
1082
|
-
"organization": "https://qualixar.com",
|
|
1083
|
-
},
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
# -- Helpers ------------------------------------------------------------------
|
|
1088
|
-
|
|
1089
|
-
def _format_results(results) -> list[dict]:
|
|
1090
|
-
"""Convert RetrievalResult list to serialisable dicts."""
|
|
1091
|
-
items: list[dict] = []
|
|
1092
|
-
for r in results:
|
|
1093
|
-
items.append({
|
|
1094
|
-
"fact_id": r.fact.fact_id,
|
|
1095
|
-
"content": r.fact.content,
|
|
1096
|
-
"score": round(r.score, 3),
|
|
1097
|
-
"confidence": round(r.confidence, 3),
|
|
1098
|
-
"relevance_score": round(
|
|
1099
|
-
getattr(r, "relevance_score", r.score) or 0.0, 3
|
|
1100
|
-
),
|
|
1101
|
-
"ranking_score": getattr(r, "ranking_score", None),
|
|
1102
|
-
"memory_confidence": round(
|
|
1103
|
-
getattr(r, "memory_confidence", r.confidence) or 0.0, 3
|
|
1104
|
-
),
|
|
1105
|
-
"rank_position": int(getattr(r, "rank_position", 0) or 0),
|
|
1106
|
-
"trust_score": round(r.trust_score, 3),
|
|
1107
|
-
"fact_type": r.fact.fact_type.value,
|
|
1108
|
-
"channel_scores": {
|
|
1109
|
-
k: round(v, 3) for k, v in r.channel_scores.items()
|
|
1110
|
-
},
|
|
1111
|
-
})
|
|
1112
|
-
return items
|