superlocalmemory 4.1.13 → 4.1.15
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 +103 -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,958 +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.1 — Active Memory MCP Tools.
|
|
6
|
-
|
|
7
|
-
session_init — Auto-recall project context at session start.
|
|
8
|
-
observe — Monitor conversation for auto-capture (decisions/bugs/prefs).
|
|
9
|
-
report_feedback — Record explicit feedback on recall results for learning.
|
|
10
|
-
|
|
11
|
-
These tools transform SLM from a passive database into an active
|
|
12
|
-
intelligence layer that learns and improves over time.
|
|
13
|
-
|
|
14
|
-
Part of Qualixar | Author: Varun Pratap Bhardwaj
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
from __future__ import annotations
|
|
18
|
-
|
|
19
|
-
import asyncio
|
|
20
|
-
import datetime
|
|
21
|
-
import logging
|
|
22
|
-
import uuid
|
|
23
|
-
from typing import TYPE_CHECKING, Callable
|
|
24
|
-
|
|
25
|
-
from mcp.types import ToolAnnotations
|
|
26
|
-
|
|
27
|
-
from superlocalmemory.core.admission import admits
|
|
28
|
-
from superlocalmemory.core.operation_request import OperationKind
|
|
29
|
-
from superlocalmemory.infra.data_root import state_path
|
|
30
|
-
from superlocalmemory.mcp.shared import authorize_mcp_mutation
|
|
31
|
-
from superlocalmemory.storage.read_connection import ReadConnectionFactory
|
|
32
|
-
|
|
33
|
-
if TYPE_CHECKING:
|
|
34
|
-
from superlocalmemory.mcp._pool_adapter import PoolRecallResponse
|
|
35
|
-
|
|
36
|
-
logger = logging.getLogger(__name__)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def _sqlite_emergency_recall(
|
|
40
|
-
query: str, limit: int, profile_id: str = "default",
|
|
41
|
-
max_age_days: int = 30,
|
|
42
|
-
) -> "PoolRecallResponse":
|
|
43
|
-
"""Emergency fallback: direct SQLite FTS5 BM25 when daemon is unreachable.
|
|
44
|
-
|
|
45
|
-
Uses the same ``atomic_facts_fts`` virtual table the daemon uses, with
|
|
46
|
-
native BM25 ranking via ``ORDER BY fts.rank``. This is the Mem0 / Letta
|
|
47
|
-
industry pattern — multi-process safe via SQLite WAL mode.
|
|
48
|
-
|
|
49
|
-
Quality degraded vs the full recall path (no semantic, no entity graph, no
|
|
50
|
-
temporal/spreading-activation/Hopfield) but still provides real BM25
|
|
51
|
-
math + age gate. Returns ``degraded_mode=True`` via the caller's flag.
|
|
52
|
-
|
|
53
|
-
Used ONLY when Tier-1 (full daemon recall) fails completely. Normal
|
|
54
|
-
path is the full five-producer fusion + entity-graph enhancement;
|
|
55
|
-
this is the fire-alarm.
|
|
56
|
-
"""
|
|
57
|
-
import re
|
|
58
|
-
|
|
59
|
-
from superlocalmemory.mcp._pool_adapter import PoolFact, PoolRecallItem, PoolRecallResponse
|
|
60
|
-
try:
|
|
61
|
-
# FTS5 MATCH syntax: tokenize the query, drop special characters
|
|
62
|
-
# that confuse the parser (/, :, ., etc), and join with OR for
|
|
63
|
-
# broadest matching. Wrap each term in quotes to escape any
|
|
64
|
-
# remaining special-meaning chars.
|
|
65
|
-
tokens = re.findall(r"[A-Za-z0-9]+", query)
|
|
66
|
-
tokens = [t for t in tokens if len(t) >= 2]
|
|
67
|
-
if not tokens:
|
|
68
|
-
return PoolRecallResponse()
|
|
69
|
-
safe_query = " OR ".join(f'"{t}"' for t in tokens)
|
|
70
|
-
age_clause = (
|
|
71
|
-
f"AND f.created_at >= datetime('now', '-{int(max_age_days)} days') "
|
|
72
|
-
if max_age_days > 0 else ""
|
|
73
|
-
)
|
|
74
|
-
memory_db = state_path("memory.db").resolve()
|
|
75
|
-
conn = ReadConnectionFactory(memory_db, timeout_ms=250).open()
|
|
76
|
-
try:
|
|
77
|
-
rows = conn.execute(
|
|
78
|
-
f"""SELECT f.fact_id, f.content, f.memory_id, f.created_at,
|
|
79
|
-
fts.rank AS bm25_rank
|
|
80
|
-
FROM atomic_facts_fts AS fts
|
|
81
|
-
JOIN atomic_facts AS f ON f.fact_id = fts.fact_id
|
|
82
|
-
WHERE fts.atomic_facts_fts MATCH ?
|
|
83
|
-
AND f.profile_id = ?
|
|
84
|
-
{age_clause}
|
|
85
|
-
ORDER BY fts.rank
|
|
86
|
-
LIMIT ?""",
|
|
87
|
-
(safe_query, profile_id, limit * 2),
|
|
88
|
-
).fetchall()
|
|
89
|
-
finally:
|
|
90
|
-
conn.close()
|
|
91
|
-
# FTS5 rank is negative (lower = better). Normalize to [0.3, 0.9].
|
|
92
|
-
if not rows:
|
|
93
|
-
return PoolRecallResponse()
|
|
94
|
-
ranks = [r[4] for r in rows]
|
|
95
|
-
rmin, rmax = min(ranks), max(ranks)
|
|
96
|
-
rng = (rmax - rmin) or 1.0
|
|
97
|
-
items = [
|
|
98
|
-
PoolRecallItem(
|
|
99
|
-
fact=PoolFact(
|
|
100
|
-
fact_id=r[0] or "", content=r[1] or "",
|
|
101
|
-
memory_id=r[2] or "", created_at=r[3] or "",
|
|
102
|
-
),
|
|
103
|
-
score=round(0.3 + 0.6 * (1.0 - (r[4] - rmin) / rng), 3),
|
|
104
|
-
)
|
|
105
|
-
for r in rows
|
|
106
|
-
]
|
|
107
|
-
logger.warning(
|
|
108
|
-
"session_init: EMERGENCY FTS5 fallback (%d results). "
|
|
109
|
-
"Daemon unreachable — semantic/graph channels disabled.", len(items),
|
|
110
|
-
)
|
|
111
|
-
return PoolRecallResponse(results=items[:limit])
|
|
112
|
-
except Exception as exc:
|
|
113
|
-
logger.warning("Emergency FTS5 fallback failed: %s", exc)
|
|
114
|
-
return PoolRecallResponse()
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
def _get_agent_id(default: str = "mcp_client") -> str:
|
|
118
|
-
"""Resolve the calling agent's ID for attribution.
|
|
119
|
-
|
|
120
|
-
Priority chain (v3.6.10+):
|
|
121
|
-
1. ContextVar set by HTTP URL path (/mcp/{agent_id}) — HTTP transport.
|
|
122
|
-
2. SLM_AGENT_ID env var — stdio transport per-process identity.
|
|
123
|
-
3. Provided default (legacy "mcp_client").
|
|
124
|
-
"""
|
|
125
|
-
from superlocalmemory.mcp.agent_context import get_current_agent_id
|
|
126
|
-
resolved = get_current_agent_id(env_fallback=True)
|
|
127
|
-
return resolved if resolved != "mcp_client" else default
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def _emit_event(event_type: str, payload: dict | None = None,
|
|
131
|
-
source_agent: str | None = None) -> None: # V3.3.12: see also mcp/shared.py
|
|
132
|
-
"""Emit an event to the EventBus (best-effort, never raises).
|
|
133
|
-
|
|
134
|
-
Dashboard visibility is load-bearing per the v3.4.26 user contract,
|
|
135
|
-
so we log on failure rather than silently dropping the signal.
|
|
136
|
-
"""
|
|
137
|
-
resolved_agent = source_agent if source_agent is not None else _get_agent_id()
|
|
138
|
-
try:
|
|
139
|
-
from superlocalmemory.infra.event_bus import EventBus
|
|
140
|
-
bus = EventBus.get_instance(str(state_path("memory.db")))
|
|
141
|
-
bus.emit(event_type, payload=payload, source_agent=resolved_agent,
|
|
142
|
-
source_protocol="mcp")
|
|
143
|
-
except Exception as exc:
|
|
144
|
-
logger.warning("event emit failed: type=%s err=%s", event_type, exc)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
# ---------------------------------------------------------------------------
|
|
148
|
-
# Canonical learning-store feedback (issues #102, #106)
|
|
149
|
-
#
|
|
150
|
-
# learning.db is the single store every learning consumer reads. Within it the
|
|
151
|
-
# canonical tables are ``learning_signals`` + ``learning_features``: the phase
|
|
152
|
-
# gate (recall_pipeline), the dashboard Living Brain panel, the ranker-phase
|
|
153
|
-
# card, and the retrainer all resolve their phase from ``learning_signals``.
|
|
154
|
-
# ``learning_feedback`` is the pre-v3.4.22 table that legacy_migration copies
|
|
155
|
-
# forward into it.
|
|
156
|
-
#
|
|
157
|
-
# Recall itself is deliberately read-only and must never open a writer, so an
|
|
158
|
-
# explicit feedback command is the only durable writer in the design. These
|
|
159
|
-
# helpers are that writer, and — per issue #106 — they report the SAME number
|
|
160
|
-
# the gate and the dashboard use. There is deliberately no fall back to a
|
|
161
|
-
# different store's count: a cross-store fallback is what let a total write
|
|
162
|
-
# failure still return "success" beside a plausibly incrementing counter.
|
|
163
|
-
# ---------------------------------------------------------------------------
|
|
164
|
-
|
|
165
|
-
_FEEDBACK_SIGNAL_MAP: dict[str, tuple[str, float]] = {
|
|
166
|
-
"relevant": ("user_positive", 1.0),
|
|
167
|
-
"irrelevant": ("user_negative", 0.0),
|
|
168
|
-
"partial": ("user_correction", 0.5),
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
def _learning_db_path():
|
|
173
|
-
"""Resolve the canonical learning.db path."""
|
|
174
|
-
return state_path("learning.db")
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
def _phase_thresholds() -> tuple[int, int]:
|
|
178
|
-
"""Return the (phase 2, phase 3) signal thresholds.
|
|
179
|
-
|
|
180
|
-
Sourced from ``learning.ranker`` so the MCP surface can never report a
|
|
181
|
-
different phase than the one recall actually applies. Falls back to the
|
|
182
|
-
documented defaults only if the learning package is unavailable.
|
|
183
|
-
"""
|
|
184
|
-
try:
|
|
185
|
-
from superlocalmemory.learning.ranker import (
|
|
186
|
-
PHASE_2_THRESHOLD,
|
|
187
|
-
PHASE_3_THRESHOLD,
|
|
188
|
-
)
|
|
189
|
-
return PHASE_2_THRESHOLD, PHASE_3_THRESHOLD
|
|
190
|
-
except Exception: # pragma: no cover — learning extras absent
|
|
191
|
-
return 50, 200
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
_PHASE_2_THRESHOLD, _PHASE_3_THRESHOLD = _phase_thresholds()
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
def _phase_for_signal_count(count: int) -> int:
|
|
198
|
-
"""Map a canonical signal count onto the adaptive ranking phase."""
|
|
199
|
-
if count < _PHASE_2_THRESHOLD:
|
|
200
|
-
return 1
|
|
201
|
-
return 2 if count < _PHASE_3_THRESHOLD else 3
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
def _record_canonical_feedback(
|
|
205
|
-
*, profile_id: str, fact_id: str, feedback: str, query: str = "",
|
|
206
|
-
channel: str = "explicit",
|
|
207
|
-
) -> bool:
|
|
208
|
-
"""Write explicit feedback to learning.db. Returns True on success.
|
|
209
|
-
|
|
210
|
-
True means the ``learning_signals`` row that every phase counter reads
|
|
211
|
-
actually landed — not merely that some row was written somewhere. The
|
|
212
|
-
outcome is RETURNED rather than swallowed so the caller can tell the user
|
|
213
|
-
the truth about whether the write was durable.
|
|
214
|
-
"""
|
|
215
|
-
signal_type, value = _FEEDBACK_SIGNAL_MAP.get(
|
|
216
|
-
feedback, ("user_correction", 0.5),
|
|
217
|
-
)
|
|
218
|
-
try:
|
|
219
|
-
from superlocalmemory.learning.feedback import FeedbackCollector
|
|
220
|
-
|
|
221
|
-
collector = FeedbackCollector(_learning_db_path())
|
|
222
|
-
write = collector.record_explicit_event(
|
|
223
|
-
profile_id=profile_id,
|
|
224
|
-
fact_id=fact_id,
|
|
225
|
-
signal_type=signal_type,
|
|
226
|
-
value=value,
|
|
227
|
-
query=query,
|
|
228
|
-
channel=channel,
|
|
229
|
-
)
|
|
230
|
-
return write.canonical
|
|
231
|
-
except Exception as exc:
|
|
232
|
-
logger.warning(
|
|
233
|
-
"canonical feedback write failed (fact_id=%s): %s", fact_id, exc,
|
|
234
|
-
)
|
|
235
|
-
return False
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
def _canonical_feedback_count(profile_id: str) -> int | None:
|
|
239
|
-
"""Count the store that gates the adaptive phases.
|
|
240
|
-
|
|
241
|
-
Returns None when the store cannot be read. The caller must NOT substitute
|
|
242
|
-
a count from a different table: before issue #106 an unreadable learning.db
|
|
243
|
-
silently fell back to ``feedback_records`` in memory.db — a table no
|
|
244
|
-
consumer reads — so the user watched a fabricated counter climb toward a
|
|
245
|
-
threshold that nothing was measuring, while the durable write did nothing.
|
|
246
|
-
"""
|
|
247
|
-
try:
|
|
248
|
-
from superlocalmemory.learning.feedback import FeedbackCollector
|
|
249
|
-
|
|
250
|
-
return FeedbackCollector(
|
|
251
|
-
_learning_db_path(),
|
|
252
|
-
).get_signal_count(profile_id)
|
|
253
|
-
except Exception as exc:
|
|
254
|
-
logger.warning("canonical feedback count failed: %s", exc)
|
|
255
|
-
return None
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
# How far ahead a session looks for scheduled facts, and how many it shows.
|
|
259
|
-
# A session preamble is not a calendar: a long horizon or a large cap turns a
|
|
260
|
-
# useful heads-up into a wall of text nobody reads.
|
|
261
|
-
_SCHEDULED_HORIZON_DAYS = 14
|
|
262
|
-
_SCHEDULED_LIMIT = 5
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
def _upcoming_scheduled_facts(engine, now: datetime.datetime) -> list[dict]:
|
|
266
|
-
"""Facts scheduled from today through the horizon, soonest first.
|
|
267
|
-
|
|
268
|
-
Bounded and index-backed, because this runs on every session start. Returns
|
|
269
|
-
an empty list on any failure: a session must still open when this query
|
|
270
|
-
cannot answer, so the caller omits the surface entirely rather than showing
|
|
271
|
-
an empty section that reads like a defect.
|
|
272
|
-
|
|
273
|
-
Selects on the stored type of the fact, which is a classification recorded at
|
|
274
|
-
write time. It is unrelated to the similarly named retrieval channel despite
|
|
275
|
-
sharing the word.
|
|
276
|
-
"""
|
|
277
|
-
try:
|
|
278
|
-
db = getattr(engine, "_db", None) or getattr(engine, "db", None)
|
|
279
|
-
if db is None or not hasattr(db, "execute"):
|
|
280
|
-
return []
|
|
281
|
-
# Both 'YYYY-MM-DD' and full timestamps compare correctly as text,
|
|
282
|
-
# because ISO-8601 orders lexicographically. The upper bound is
|
|
283
|
-
# exclusive, so the horizon day itself is included.
|
|
284
|
-
start = now.date().isoformat()
|
|
285
|
-
end = (now + datetime.timedelta(days=_SCHEDULED_HORIZON_DAYS + 1)).date().isoformat()
|
|
286
|
-
rows = db.execute(
|
|
287
|
-
"SELECT fact_id, content, referenced_date"
|
|
288
|
-
" FROM atomic_facts"
|
|
289
|
-
" WHERE profile_id = ?"
|
|
290
|
-
" AND fact_type = 'prospective'"
|
|
291
|
-
" AND referenced_date IS NOT NULL"
|
|
292
|
-
" AND referenced_date >= ?"
|
|
293
|
-
" AND referenced_date < ?"
|
|
294
|
-
" ORDER BY referenced_date ASC"
|
|
295
|
-
f" LIMIT {_SCHEDULED_LIMIT}",
|
|
296
|
-
(engine.profile_id, start, end),
|
|
297
|
-
)
|
|
298
|
-
return [
|
|
299
|
-
{"fact_id": r["fact_id"], "content": r["content"],
|
|
300
|
-
"scheduled_at": r["referenced_date"]}
|
|
301
|
-
for r in rows
|
|
302
|
-
]
|
|
303
|
-
except Exception as exc:
|
|
304
|
-
logger.warning("scheduled-fact surface failed: %s", exc)
|
|
305
|
-
return []
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
def register_active_tools(server, get_engine: Callable) -> None:
|
|
309
|
-
"""Register 3 active memory tools on *server*."""
|
|
310
|
-
|
|
311
|
-
# ------------------------------------------------------------------
|
|
312
|
-
# 1. session_init — Auto-recall project context at session start
|
|
313
|
-
# ------------------------------------------------------------------
|
|
314
|
-
@server.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
315
|
-
@admits(OperationKind.RECALL)
|
|
316
|
-
async def session_init(
|
|
317
|
-
project_path: str = "",
|
|
318
|
-
query: str = "",
|
|
319
|
-
max_results: int = 10,
|
|
320
|
-
max_age_days: int = 30,
|
|
321
|
-
session_id: str = "",
|
|
322
|
-
agent_id: str = "",
|
|
323
|
-
) -> dict:
|
|
324
|
-
"""Initialize session with relevant memory context.
|
|
325
|
-
|
|
326
|
-
Call this ONCE at the start of every session. Returns:
|
|
327
|
-
- Recent decisions and patterns for this project
|
|
328
|
-
- Top relevant memories based on project path or query
|
|
329
|
-
- Learning status (signal count, ranking phase)
|
|
330
|
-
|
|
331
|
-
The AI should call this automatically before any other work.
|
|
332
|
-
|
|
333
|
-
Parameters:
|
|
334
|
-
project_path: Working directory path. Used to build the search query
|
|
335
|
-
when no explicit query is provided.
|
|
336
|
-
query: Override the search query. If omitted, derived from project_path
|
|
337
|
-
or falls back to "recent important decisions".
|
|
338
|
-
max_results: Maximum memories to return (default: 10).
|
|
339
|
-
max_age_days: Suppress memories older than this many days unless their
|
|
340
|
-
relevance score is ≥ 0.70 (architectural decisions that remain
|
|
341
|
-
permanently relevant still surface). Default: 30.
|
|
342
|
-
Set to 0 to disable the age gate entirely.
|
|
343
|
-
"""
|
|
344
|
-
try:
|
|
345
|
-
from superlocalmemory.hooks.rules_engine import RulesEngine
|
|
346
|
-
from superlocalmemory.mcp._pool_adapter import pool_recall
|
|
347
|
-
|
|
348
|
-
engine = get_engine()
|
|
349
|
-
rules = RulesEngine(config_path=state_path("config.json"))
|
|
350
|
-
|
|
351
|
-
if not rules.should_recall("session_start"):
|
|
352
|
-
return {
|
|
353
|
-
"success": True,
|
|
354
|
-
"context": "",
|
|
355
|
-
"memories": [],
|
|
356
|
-
"message": "Auto-recall disabled",
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
recall_config = rules.get_recall_config()
|
|
360
|
-
relevance_threshold = recall_config.get("relevance_threshold", 0.3)
|
|
361
|
-
if query:
|
|
362
|
-
search_query = query
|
|
363
|
-
elif project_path:
|
|
364
|
-
search_query = f"project context {project_path}"
|
|
365
|
-
else:
|
|
366
|
-
search_query = "recent important decisions"
|
|
367
|
-
|
|
368
|
-
# 2-tier recall (industry pattern: Hindsight / Zep / Supermemory):
|
|
369
|
-
# PRIMARY: full recall via daemon — five candidate producers (semantic
|
|
370
|
-
# + BM25 + temporal + Hopfield + spreading-activation) into RRF
|
|
371
|
-
# fusion, then entity-graph post-fusion enhancement, FSRS decay.
|
|
372
|
-
# Fast because Ollama embed model is kept warm (keep_alive=-1
|
|
373
|
-
# + eager pre-warm at daemon boot).
|
|
374
|
-
# EMERGENCY: direct FTS5 BM25 (Mem0 / Letta pattern). Used ONLY when
|
|
375
|
-
# daemon is completely unreachable. Returns degraded_mode=True.
|
|
376
|
-
from superlocalmemory.mcp._pool_adapter import PoolError
|
|
377
|
-
degraded_mode = False
|
|
378
|
-
try:
|
|
379
|
-
# v3.6.9-audit: pool_recall uses blocking urllib under the hood
|
|
380
|
-
# (DaemonPoolProxy.recall → urllib.urlopen). Must run in a
|
|
381
|
-
# thread so the async MCP event loop is not stalled — same
|
|
382
|
-
# fix class as #34 mesh tools deadlock.
|
|
383
|
-
response = await asyncio.to_thread(
|
|
384
|
-
pool_recall, search_query, limit=max_results, fast=None,
|
|
385
|
-
)
|
|
386
|
-
except (PoolError, Exception) as exc:
|
|
387
|
-
logger.warning(
|
|
388
|
-
"session_init: daemon recall failed (%s) — using FTS5 emergency fallback. "
|
|
389
|
-
"Memory system is in DEGRADED MODE: semantic/graph channels unavailable.",
|
|
390
|
-
exc,
|
|
391
|
-
)
|
|
392
|
-
response = _sqlite_emergency_recall(
|
|
393
|
-
search_query, max_results,
|
|
394
|
-
profile_id=engine.profile_id,
|
|
395
|
-
max_age_days=max_age_days,
|
|
396
|
-
)
|
|
397
|
-
degraded_mode = True
|
|
398
|
-
|
|
399
|
-
# Age gate: suppress stale memories at session start.
|
|
400
|
-
# Memories older than max_age_days are excluded unless their score
|
|
401
|
-
# exceeds 0.7 (high-relevance architectural decisions always surface).
|
|
402
|
-
# max_age_days=0 disables the gate entirely.
|
|
403
|
-
from datetime import UTC
|
|
404
|
-
from datetime import datetime as _dt
|
|
405
|
-
_now = _dt.now(UTC)
|
|
406
|
-
|
|
407
|
-
def _age_days(created_at_str: str) -> float:
|
|
408
|
-
if not created_at_str:
|
|
409
|
-
return 0.0
|
|
410
|
-
try:
|
|
411
|
-
created = _dt.fromisoformat(
|
|
412
|
-
created_at_str.replace("Z", "+00:00")
|
|
413
|
-
)
|
|
414
|
-
return max(0.0, (_now - created).total_seconds() / 86400.0)
|
|
415
|
-
except (ValueError, TypeError):
|
|
416
|
-
return 0.0
|
|
417
|
-
|
|
418
|
-
relevant = [
|
|
419
|
-
r for r in response.results
|
|
420
|
-
if r.score >= relevance_threshold
|
|
421
|
-
and (
|
|
422
|
-
max_age_days <= 0
|
|
423
|
-
or _age_days(r.fact.created_at) <= max_age_days
|
|
424
|
-
or r.score >= 0.7
|
|
425
|
-
)
|
|
426
|
-
]
|
|
427
|
-
|
|
428
|
-
# Build both return shapes from one recall. Calling recall twice
|
|
429
|
-
# doubles session startup latency and can return duplicate snippets.
|
|
430
|
-
|
|
431
|
-
# v3.4.65: use shared injection formatter for full-fidelity context.
|
|
432
|
-
from superlocalmemory.core.injection import (
|
|
433
|
-
InjectableMemory,
|
|
434
|
-
clamp_content,
|
|
435
|
-
is_low_quality,
|
|
436
|
-
render_context,
|
|
437
|
-
sanitize_untrusted_content,
|
|
438
|
-
)
|
|
439
|
-
|
|
440
|
-
pid = engine.profile_id
|
|
441
|
-
|
|
442
|
-
# Merge pinned facts (Q3: Core Memory explicit pins).
|
|
443
|
-
# Pinned facts surface even if the query didn't retrieve them.
|
|
444
|
-
try:
|
|
445
|
-
pinned_facts = engine.db.get_pinned(pid)
|
|
446
|
-
except Exception:
|
|
447
|
-
pinned_facts = []
|
|
448
|
-
pinned_seen = set()
|
|
449
|
-
|
|
450
|
-
cfg_inj = getattr(getattr(engine, "config", None), "injection", None)
|
|
451
|
-
# Defend against MagicMock / non-config objects in tests.
|
|
452
|
-
try:
|
|
453
|
-
from superlocalmemory.core.config import InjectionConfig
|
|
454
|
-
if not isinstance(cfg_inj, InjectionConfig):
|
|
455
|
-
cfg_inj = None
|
|
456
|
-
except Exception:
|
|
457
|
-
cfg_inj = None
|
|
458
|
-
|
|
459
|
-
inj_mems: list[InjectableMemory] = []
|
|
460
|
-
# Pinned facts first (they always head the core block).
|
|
461
|
-
for pf in pinned_facts[:20]: # safety cap
|
|
462
|
-
inj_mems.append(InjectableMemory(
|
|
463
|
-
content=pf.content,
|
|
464
|
-
score=0.0,
|
|
465
|
-
fact_id=pf.fact_id,
|
|
466
|
-
importance=getattr(pf, "importance", 0.0) or 0.0,
|
|
467
|
-
access_count=getattr(pf, "access_count", 0) or 0,
|
|
468
|
-
pinned=True,
|
|
469
|
-
source_type="pinned-fact",
|
|
470
|
-
))
|
|
471
|
-
pinned_seen.add(pf.fact_id)
|
|
472
|
-
|
|
473
|
-
# Then recall results (skip duplicates of pinned).
|
|
474
|
-
for r in relevant[:max_results]:
|
|
475
|
-
if r.fact.fact_id in pinned_seen:
|
|
476
|
-
continue
|
|
477
|
-
inj_mems.append(InjectableMemory(
|
|
478
|
-
content=r.fact.content,
|
|
479
|
-
score=round(r.score, 3),
|
|
480
|
-
fact_id=r.fact.fact_id,
|
|
481
|
-
importance=getattr(r.fact, "importance", 0.0) or 0.0,
|
|
482
|
-
access_count=getattr(r.fact, "access_count", 0) or 0,
|
|
483
|
-
source_type="recall",
|
|
484
|
-
))
|
|
485
|
-
|
|
486
|
-
mode_str = str(getattr(engine, "mode", "B")).upper()
|
|
487
|
-
try:
|
|
488
|
-
context = render_context(
|
|
489
|
-
inj_mems, mode=mode_str, cfg=cfg_inj, wrap=True,
|
|
490
|
-
)
|
|
491
|
-
except Exception:
|
|
492
|
-
# Fail closed: never serialize retrieved content through a
|
|
493
|
-
# weaker ad-hoc path when the mandatory renderer fails.
|
|
494
|
-
context = ""
|
|
495
|
-
|
|
496
|
-
# Live soft-prompt injection (Phase 5): prepend the profile's behavioral
|
|
497
|
-
# soft prompt so it reaches the session_init context agents actually
|
|
498
|
-
# consume (same engine->AutoInvoker bridge AutoRecall uses). Fail-soft.
|
|
499
|
-
try:
|
|
500
|
-
_sp_getter = getattr(
|
|
501
|
-
getattr(engine, "_auto_invoker", None),
|
|
502
|
-
"_get_soft_prompt_text", None,
|
|
503
|
-
)
|
|
504
|
-
_soft_prompt = _sp_getter() if callable(_sp_getter) else ""
|
|
505
|
-
if _soft_prompt:
|
|
506
|
-
context = f"{_soft_prompt}\n\n{context}" if context else _soft_prompt
|
|
507
|
-
except Exception as exc:
|
|
508
|
-
logger.warning("session_init soft-prompt injection failed: %s", exc)
|
|
509
|
-
|
|
510
|
-
# GAP-FIX (v3.4.65 delivery-lead): the memories[] array is part of
|
|
511
|
-
# the MCP response Claude Code ingests — it MUST be bounded too, not
|
|
512
|
-
# just the rendered `context` string. Previously full unclamped
|
|
513
|
-
# content shipped here (one fact was 131K chars → ~124K-token
|
|
514
|
-
# response, defeating the whole token budget). Clamp each content
|
|
515
|
-
# to per_memory_max_tokens, drop junk, and honour max_results.
|
|
516
|
-
contract_by_id = {
|
|
517
|
-
r.fact.fact_id: r for r in relevant[:max_results]
|
|
518
|
-
}
|
|
519
|
-
memories = []
|
|
520
|
-
for position, m in enumerate(inj_mems[:max_results], start=1):
|
|
521
|
-
if is_low_quality(m.content):
|
|
522
|
-
continue
|
|
523
|
-
result_contract = contract_by_id.get(m.fact_id)
|
|
524
|
-
relevance = (
|
|
525
|
-
getattr(result_contract, "relevance_score", m.score)
|
|
526
|
-
if result_contract is not None else m.score
|
|
527
|
-
)
|
|
528
|
-
memory_confidence = (
|
|
529
|
-
getattr(result_contract, "memory_confidence", None)
|
|
530
|
-
if result_contract is not None else None
|
|
531
|
-
)
|
|
532
|
-
memories.append({
|
|
533
|
-
"fact_id": m.fact_id,
|
|
534
|
-
"content": clamp_content(
|
|
535
|
-
sanitize_untrusted_content(m.content), cfg_inj,
|
|
536
|
-
),
|
|
537
|
-
"score": m.score,
|
|
538
|
-
"relevance_score": relevance,
|
|
539
|
-
"ranking_score": (
|
|
540
|
-
getattr(result_contract, "ranking_score", None)
|
|
541
|
-
if result_contract is not None else None
|
|
542
|
-
),
|
|
543
|
-
"confidence": memory_confidence,
|
|
544
|
-
"memory_confidence": memory_confidence,
|
|
545
|
-
"rank_position": (
|
|
546
|
-
getattr(result_contract, "rank_position", position)
|
|
547
|
-
if result_contract is not None else position
|
|
548
|
-
),
|
|
549
|
-
"is_core": m.is_core,
|
|
550
|
-
"untrusted": True,
|
|
551
|
-
"source_type": m.source_type,
|
|
552
|
-
})
|
|
553
|
-
|
|
554
|
-
# Learning status — issue #106: read the SAME canonical counter
|
|
555
|
-
# that report_feedback reports, the recall gate applies, and the
|
|
556
|
-
# dashboard displays. This used to read ``feedback_records`` in
|
|
557
|
-
# memory.db, so session_init and report_feedback returned two
|
|
558
|
-
# different "signal" totals for one profile in the same session.
|
|
559
|
-
# A silent zero masks wiring bugs, so a failed read is logged.
|
|
560
|
-
feedback_count = _canonical_feedback_count(pid)
|
|
561
|
-
if feedback_count is None:
|
|
562
|
-
logger.warning(
|
|
563
|
-
"session_init canonical signal count unavailable for "
|
|
564
|
-
"profile %s; reporting 0", pid,
|
|
565
|
-
)
|
|
566
|
-
feedback_count = 0
|
|
567
|
-
|
|
568
|
-
# A gateway can serve concurrent host conversations. An explicit
|
|
569
|
-
# host id therefore always wins; generating one is retained only
|
|
570
|
-
# for older clients that cannot supply lifecycle identity.
|
|
571
|
-
effective_session_id = session_id.strip() or (
|
|
572
|
-
f"slm-{datetime.datetime.now(datetime.timezone.utc):%Y%m%d}"
|
|
573
|
-
f"-{uuid.uuid4().hex[:8]}"
|
|
574
|
-
)
|
|
575
|
-
effective_agent_id = agent_id.strip() or _get_agent_id()
|
|
576
|
-
# Backward-compatible default for legacy close_session() callers;
|
|
577
|
-
# native hosts must pass their explicit id when sessions overlap.
|
|
578
|
-
engine._last_session_id = effective_session_id
|
|
579
|
-
|
|
580
|
-
_upcoming_events = _upcoming_scheduled_facts(engine, _now)
|
|
581
|
-
|
|
582
|
-
return {
|
|
583
|
-
"success": True,
|
|
584
|
-
"session_id": effective_session_id,
|
|
585
|
-
"agent_id": effective_agent_id,
|
|
586
|
-
"context": context,
|
|
587
|
-
"memories": memories[:max_results],
|
|
588
|
-
"memory_count": len(memories),
|
|
589
|
-
"core_memory": [m["content"] for m in memories if m.get("is_core")],
|
|
590
|
-
"degraded_mode": degraded_mode,
|
|
591
|
-
"retrieval_mode": (
|
|
592
|
-
"emergency_fts5_bm25"
|
|
593
|
-
if degraded_mode
|
|
594
|
-
else "hybrid_candidate_fusion"
|
|
595
|
-
),
|
|
596
|
-
"score_contract_version": getattr(
|
|
597
|
-
response, "score_contract_version", "2"
|
|
598
|
-
),
|
|
599
|
-
"calibration_status": getattr(
|
|
600
|
-
response, "calibration_status", "uncalibrated"
|
|
601
|
-
),
|
|
602
|
-
"calibration_id": getattr(response, "calibration_id", None),
|
|
603
|
-
"answer_confidence": getattr(response, "answer_confidence", None),
|
|
604
|
-
"abstained": getattr(response, "abstained", not bool(relevant)),
|
|
605
|
-
"abstention_reason": getattr(response, "abstention_reason", None),
|
|
606
|
-
"learning": {
|
|
607
|
-
"feedback_signals": feedback_count,
|
|
608
|
-
"phase": _phase_for_signal_count(feedback_count),
|
|
609
|
-
"status": (
|
|
610
|
-
"collecting"
|
|
611
|
-
if feedback_count < _PHASE_2_THRESHOLD
|
|
612
|
-
else "learning"
|
|
613
|
-
if feedback_count < _PHASE_3_THRESHOLD
|
|
614
|
-
else "trained"
|
|
615
|
-
),
|
|
616
|
-
},
|
|
617
|
-
# Scheduled-event surface: present only when facts exist in the
|
|
618
|
-
# 14-day window. Absent means the window is empty, not an error.
|
|
619
|
-
**( {"upcoming_events": _upcoming_events}
|
|
620
|
-
if _upcoming_events else {} ),
|
|
621
|
-
}
|
|
622
|
-
except Exception as exc:
|
|
623
|
-
logger.exception("session_init failed")
|
|
624
|
-
return {"success": False, "error": str(exc)}
|
|
625
|
-
|
|
626
|
-
# ------------------------------------------------------------------
|
|
627
|
-
# 2. observe — Auto-capture decisions/bugs/preferences
|
|
628
|
-
# ------------------------------------------------------------------
|
|
629
|
-
@server.tool()
|
|
630
|
-
@admits(OperationKind.REMEMBER)
|
|
631
|
-
async def observe(
|
|
632
|
-
content: str,
|
|
633
|
-
agent_id: str | None = None,
|
|
634
|
-
session_id: str = "",
|
|
635
|
-
) -> dict:
|
|
636
|
-
"""Observe conversation content for automatic memory capture.
|
|
637
|
-
|
|
638
|
-
Send conversation snippets here. The system evaluates whether
|
|
639
|
-
the content contains decisions, bug fixes, or preferences worth
|
|
640
|
-
storing. If so, it auto-captures them with classification metadata.
|
|
641
|
-
|
|
642
|
-
Call this after making decisions, fixing bugs, or expressing preferences.
|
|
643
|
-
The system will NOT store low-confidence or irrelevant content.
|
|
644
|
-
|
|
645
|
-
v3.4.39: ``agent_id`` now defaults to the ``SLM_AGENT_ID`` env var
|
|
646
|
-
(set by each MCP client's config) so observations carry proper
|
|
647
|
-
per-agent attribution.
|
|
648
|
-
"""
|
|
649
|
-
if agent_id is None:
|
|
650
|
-
agent_id = _get_agent_id()
|
|
651
|
-
try:
|
|
652
|
-
from superlocalmemory.hooks.auto_capture import AutoCapture
|
|
653
|
-
from superlocalmemory.hooks.rules_engine import RulesEngine
|
|
654
|
-
from superlocalmemory.mcp._pool_adapter import pool_store
|
|
655
|
-
|
|
656
|
-
rules = RulesEngine(config_path=state_path("config.json"))
|
|
657
|
-
|
|
658
|
-
auto = AutoCapture(
|
|
659
|
-
store_fn=pool_store,
|
|
660
|
-
config=rules.get_capture_config(),
|
|
661
|
-
)
|
|
662
|
-
|
|
663
|
-
decision = auto.evaluate(content)
|
|
664
|
-
|
|
665
|
-
if not decision.capture:
|
|
666
|
-
return {
|
|
667
|
-
"captured": False,
|
|
668
|
-
"reason": decision.reason,
|
|
669
|
-
"category": decision.category,
|
|
670
|
-
"confidence": round(decision.confidence, 3),
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
# Check rules engine for category-level permission
|
|
674
|
-
if not rules.should_capture(decision.category, decision.confidence):
|
|
675
|
-
return {
|
|
676
|
-
"captured": False,
|
|
677
|
-
"reason": f"Category '{decision.category}' disabled in rules",
|
|
678
|
-
"category": decision.category,
|
|
679
|
-
"confidence": round(decision.confidence, 3),
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
# Auto-store via engine.
|
|
683
|
-
# pool_store uses blocking urllib (DaemonPoolProxy) — run in
|
|
684
|
-
# thread so the MCP event loop stays unblocked (#34 class).
|
|
685
|
-
from superlocalmemory.mcp.session_binding import resolve_session_id
|
|
686
|
-
effective_session_id = resolve_session_id(
|
|
687
|
-
session_id, agent_id=agent_id, allow_agent_fallback=False,
|
|
688
|
-
)
|
|
689
|
-
stored = await asyncio.to_thread(
|
|
690
|
-
auto.capture,
|
|
691
|
-
content,
|
|
692
|
-
category=decision.category,
|
|
693
|
-
metadata={"agent_id": agent_id, "session_id": effective_session_id,
|
|
694
|
-
"source": "auto-observe"},
|
|
695
|
-
)
|
|
696
|
-
|
|
697
|
-
if stored:
|
|
698
|
-
_emit_event("memory.created", {
|
|
699
|
-
"agent_id": agent_id,
|
|
700
|
-
"category": decision.category,
|
|
701
|
-
"content_preview": content[:80],
|
|
702
|
-
"source": "auto-observe",
|
|
703
|
-
}, source_agent=agent_id)
|
|
704
|
-
|
|
705
|
-
return {
|
|
706
|
-
"captured": stored,
|
|
707
|
-
"category": decision.category,
|
|
708
|
-
"confidence": round(decision.confidence, 3),
|
|
709
|
-
"reason": decision.reason,
|
|
710
|
-
"session_id": effective_session_id,
|
|
711
|
-
}
|
|
712
|
-
except Exception as exc:
|
|
713
|
-
logger.exception("observe failed")
|
|
714
|
-
return {"captured": False, "error": str(exc)}
|
|
715
|
-
|
|
716
|
-
# ------------------------------------------------------------------
|
|
717
|
-
# 3. report_feedback — Explicit feedback for learning
|
|
718
|
-
# ------------------------------------------------------------------
|
|
719
|
-
@server.tool()
|
|
720
|
-
@admits(OperationKind.REMEMBER)
|
|
721
|
-
async def report_feedback(
|
|
722
|
-
fact_id: str,
|
|
723
|
-
feedback: str = "relevant",
|
|
724
|
-
query: str = "",
|
|
725
|
-
) -> dict:
|
|
726
|
-
"""Report whether a recalled memory was useful.
|
|
727
|
-
|
|
728
|
-
feedback: "relevant" (memory was helpful), "irrelevant" (not useful),
|
|
729
|
-
"partial" (somewhat relevant).
|
|
730
|
-
|
|
731
|
-
This feedback trains the adaptive ranker to return better results
|
|
732
|
-
over time. The more feedback, the smarter the system gets.
|
|
733
|
-
"""
|
|
734
|
-
try:
|
|
735
|
-
engine = get_engine()
|
|
736
|
-
pid = engine.profile_id
|
|
737
|
-
|
|
738
|
-
if feedback not in ("relevant", "irrelevant", "partial"):
|
|
739
|
-
return {
|
|
740
|
-
"success": False,
|
|
741
|
-
"error": (
|
|
742
|
-
f"Invalid feedback: {feedback}. "
|
|
743
|
-
"Use relevant/irrelevant/partial"
|
|
744
|
-
),
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
authorization = authorize_mcp_mutation(
|
|
748
|
-
engine,
|
|
749
|
-
"update",
|
|
750
|
-
mutation_source="mcp-recall-feedback",
|
|
751
|
-
profile_id=pid,
|
|
752
|
-
fact_id=fact_id,
|
|
753
|
-
content_preview=feedback,
|
|
754
|
-
)
|
|
755
|
-
record = engine._adaptive_learner.record_feedback(
|
|
756
|
-
query=query,
|
|
757
|
-
fact_id=fact_id,
|
|
758
|
-
feedback_type=feedback,
|
|
759
|
-
profile_id=pid,
|
|
760
|
-
)
|
|
761
|
-
|
|
762
|
-
# The AdaptiveLearner write above lands in ``feedback_records`` in
|
|
763
|
-
# memory.db — a table whose only readers are AdaptiveLearner's own
|
|
764
|
-
# count and its train(), which nothing in the running system
|
|
765
|
-
# calls. It is kept so existing data and GDPR erasure stay intact,
|
|
766
|
-
# but it is NOT the learning write and its count is NOT reported.
|
|
767
|
-
#
|
|
768
|
-
# The canonical store is learning.db's ``learning_signals`` (+ the
|
|
769
|
-
# paired ``learning_features`` row). Writing there is what makes
|
|
770
|
-
# feedback do work: the recall phase gate, the dashboard Living
|
|
771
|
-
# Brain panel, the ranker-phase card, and the retrainer all read
|
|
772
|
-
# it. Recall stays read-only by design, so this explicit path is
|
|
773
|
-
# the only durable writer.
|
|
774
|
-
canonical_recorded = _record_canonical_feedback(
|
|
775
|
-
profile_id=pid,
|
|
776
|
-
fact_id=fact_id,
|
|
777
|
-
feedback=feedback,
|
|
778
|
-
query=query,
|
|
779
|
-
)
|
|
780
|
-
|
|
781
|
-
# issue #106: report the count from the store that ACTUALLY gates
|
|
782
|
-
# the phases, and report NOTHING when it cannot be read. The old
|
|
783
|
-
# fallback to ``feedback_records`` is what made a total write
|
|
784
|
-
# failure indistinguishable from success: the response carried a
|
|
785
|
-
# plausible, incrementing ``total_signals`` sourced from a table
|
|
786
|
-
# nothing consumes, so the caller had no way to notice that
|
|
787
|
-
# learning.db was never touched.
|
|
788
|
-
count = _canonical_feedback_count(pid)
|
|
789
|
-
authorization.complete()
|
|
790
|
-
|
|
791
|
-
if not canonical_recorded or count is None:
|
|
792
|
-
# Never claim a durable learning write that did not happen.
|
|
793
|
-
return {
|
|
794
|
-
"success": False,
|
|
795
|
-
"durable": False,
|
|
796
|
-
"feedback_id": record.feedback_id,
|
|
797
|
-
"total_signals": count,
|
|
798
|
-
"error": (
|
|
799
|
-
"Feedback was accepted but could not be written to "
|
|
800
|
-
"the canonical learning store (learning.db), so it "
|
|
801
|
-
"will not influence ranking. Run 'slm doctor' to "
|
|
802
|
-
"diagnose learning.db."
|
|
803
|
-
),
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
phase = _phase_for_signal_count(count)
|
|
807
|
-
_emit_event("pattern.learned", {
|
|
808
|
-
"fact_id": fact_id,
|
|
809
|
-
"feedback": feedback,
|
|
810
|
-
"total_signals": count,
|
|
811
|
-
"phase": phase,
|
|
812
|
-
})
|
|
813
|
-
|
|
814
|
-
result = {
|
|
815
|
-
"success": True,
|
|
816
|
-
"durable": True,
|
|
817
|
-
"feedback_id": record.feedback_id,
|
|
818
|
-
"total_signals": count,
|
|
819
|
-
"phase": phase,
|
|
820
|
-
"message": f"Feedback recorded. {count} total signals."
|
|
821
|
-
+ (" Phase 2 unlocked!"
|
|
822
|
-
if count == _PHASE_2_THRESHOLD else "")
|
|
823
|
-
+ (" Phase 3 (ML) unlocked!"
|
|
824
|
-
if count == _PHASE_3_THRESHOLD else ""),
|
|
825
|
-
}
|
|
826
|
-
return result
|
|
827
|
-
except Exception as exc:
|
|
828
|
-
logger.exception("report_feedback failed")
|
|
829
|
-
return {"success": False, "error": str(exc)}
|
|
830
|
-
|
|
831
|
-
# ------------------------------------------------------------------
|
|
832
|
-
# close_session — V3.3.12: Expose session closure via MCP
|
|
833
|
-
# ------------------------------------------------------------------
|
|
834
|
-
|
|
835
|
-
@server.tool()
|
|
836
|
-
@admits(OperationKind.CONSOLIDATE)
|
|
837
|
-
async def close_session(session_id: str = "") -> dict:
|
|
838
|
-
"""Close the current session and create temporal summary events.
|
|
839
|
-
|
|
840
|
-
Aggregates facts from the session into per-entity temporal summaries,
|
|
841
|
-
enabling temporal queries like "What happened in session X?"
|
|
842
|
-
|
|
843
|
-
Args:
|
|
844
|
-
session_id: Session to close. Defaults to the most recent session.
|
|
845
|
-
"""
|
|
846
|
-
try:
|
|
847
|
-
engine = get_engine()
|
|
848
|
-
sid = session_id or getattr(engine, '_last_session_id', '')
|
|
849
|
-
# v3.6.9 (#35): _last_session_id was never assigned — fall back to
|
|
850
|
-
# querying the DB for the most recent session_id instead of silently
|
|
851
|
-
# returning summary_events_created: 0.
|
|
852
|
-
if not sid:
|
|
853
|
-
try:
|
|
854
|
-
db = getattr(engine, '_db', None) or getattr(engine, 'db', None)
|
|
855
|
-
if db and hasattr(db, 'execute'):
|
|
856
|
-
rows = db.execute(
|
|
857
|
-
"SELECT session_id FROM memories "
|
|
858
|
-
"WHERE session_id != '' ORDER BY created_at DESC LIMIT 1",
|
|
859
|
-
()
|
|
860
|
-
)
|
|
861
|
-
if rows:
|
|
862
|
-
sid = str(rows[0][0])
|
|
863
|
-
except Exception:
|
|
864
|
-
pass
|
|
865
|
-
if not sid:
|
|
866
|
-
return {"success": False, "error": "No session_id provided or found"}
|
|
867
|
-
authorization = authorize_mcp_mutation(
|
|
868
|
-
engine,
|
|
869
|
-
"update",
|
|
870
|
-
mutation_source="mcp-session-close",
|
|
871
|
-
profile_id=engine.profile_id,
|
|
872
|
-
content_preview=sid,
|
|
873
|
-
)
|
|
874
|
-
count = engine.close_session(sid)
|
|
875
|
-
authorization.complete()
|
|
876
|
-
return {
|
|
877
|
-
"success": True,
|
|
878
|
-
"session_id": sid,
|
|
879
|
-
"summary_events_created": count,
|
|
880
|
-
}
|
|
881
|
-
except Exception as exc:
|
|
882
|
-
logger.exception("close_session failed")
|
|
883
|
-
return {"success": False, "error": str(exc)}
|
|
884
|
-
|
|
885
|
-
# ------------------------------------------------------------------
|
|
886
|
-
# core_memory — v3.4.65: explicit Core Memory pin management
|
|
887
|
-
# ------------------------------------------------------------------
|
|
888
|
-
|
|
889
|
-
@server.tool()
|
|
890
|
-
@admits(OperationKind.CORRECT)
|
|
891
|
-
async def core_memory(
|
|
892
|
-
action: str,
|
|
893
|
-
fact_id: str = "",
|
|
894
|
-
) -> dict:
|
|
895
|
-
"""Manage the explicit Core Memory pin set (v3.4.65).
|
|
896
|
-
|
|
897
|
-
- pin: mark a fact as always-injected
|
|
898
|
-
- unpin: clear the pin
|
|
899
|
-
- list: return currently pinned facts
|
|
900
|
-
"""
|
|
901
|
-
try:
|
|
902
|
-
engine = get_engine()
|
|
903
|
-
db = engine.db
|
|
904
|
-
# Isolation: the tenant is ALWAYS the engine's active profile. The
|
|
905
|
-
# caller-supplied profile_id is ignored — honoring it let any MCP
|
|
906
|
-
# client read/pin another profile's facts by passing profile_id.
|
|
907
|
-
pid = engine.profile_id
|
|
908
|
-
|
|
909
|
-
if action == "pin":
|
|
910
|
-
if not fact_id:
|
|
911
|
-
return {"success": False, "error": "fact_id required for pin"}
|
|
912
|
-
authorization = authorize_mcp_mutation(
|
|
913
|
-
engine,
|
|
914
|
-
"update",
|
|
915
|
-
mutation_source="mcp-core-memory-pin",
|
|
916
|
-
profile_id=pid,
|
|
917
|
-
fact_id=fact_id,
|
|
918
|
-
)
|
|
919
|
-
db.set_pinned(fact_id, True)
|
|
920
|
-
authorization.complete()
|
|
921
|
-
return {"success": True, "action": "pin", "fact_id": fact_id}
|
|
922
|
-
|
|
923
|
-
if action == "unpin":
|
|
924
|
-
if not fact_id:
|
|
925
|
-
return {"success": False, "error": "fact_id required for unpin"}
|
|
926
|
-
authorization = authorize_mcp_mutation(
|
|
927
|
-
engine,
|
|
928
|
-
"update",
|
|
929
|
-
mutation_source="mcp-core-memory-unpin",
|
|
930
|
-
profile_id=pid,
|
|
931
|
-
fact_id=fact_id,
|
|
932
|
-
)
|
|
933
|
-
db.set_pinned(fact_id, False)
|
|
934
|
-
authorization.complete()
|
|
935
|
-
return {"success": True, "action": "unpin", "fact_id": fact_id}
|
|
936
|
-
|
|
937
|
-
if action == "list":
|
|
938
|
-
pinned = db.get_pinned(pid)
|
|
939
|
-
cfg_inj = getattr(getattr(engine, "config", None), "injection", None)
|
|
940
|
-
max_tok = getattr(cfg_inj, "per_memory_max_tokens", 600) if cfg_inj else 600
|
|
941
|
-
return {
|
|
942
|
-
"success": True,
|
|
943
|
-
"pinned": [
|
|
944
|
-
{
|
|
945
|
-
"fact_id": f.fact_id,
|
|
946
|
-
"content": f.content[: max_tok * 4],
|
|
947
|
-
"importance": getattr(f, "importance", 0.0),
|
|
948
|
-
}
|
|
949
|
-
for f in pinned
|
|
950
|
-
],
|
|
951
|
-
"count": len(pinned),
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
return {"success": False, "error": f"unknown action: {action}"}
|
|
955
|
-
|
|
956
|
-
except Exception as exc:
|
|
957
|
-
logger.exception("core_memory failed")
|
|
958
|
-
return {"success": False, "error": str(exc)}
|