superlocalmemory 2.8.6 → 3.0.1
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/LICENSE +9 -1
- package/NOTICE +63 -0
- package/README.md +165 -480
- package/bin/slm +17 -449
- package/bin/slm-npm +62 -48
- package/conftest.py +5 -0
- package/docs/api-reference.md +284 -0
- package/docs/architecture.md +149 -0
- package/docs/auto-memory.md +150 -0
- package/docs/cli-reference.md +276 -0
- package/docs/compliance.md +191 -0
- package/docs/configuration.md +182 -0
- package/docs/getting-started.md +102 -0
- package/docs/ide-setup.md +261 -0
- package/docs/mcp-tools.md +220 -0
- package/docs/migration-from-v2.md +170 -0
- package/docs/profiles.md +173 -0
- package/docs/troubleshooting.md +310 -0
- package/{configs → ide/configs}/antigravity-mcp.json +3 -3
- package/ide/configs/chatgpt-desktop-mcp.json +16 -0
- package/{configs → ide/configs}/claude-desktop-mcp.json +3 -3
- package/{configs → ide/configs}/codex-mcp.toml +4 -4
- package/{configs → ide/configs}/continue-mcp.yaml +4 -3
- package/{configs → ide/configs}/continue-skills.yaml +6 -6
- package/ide/configs/cursor-mcp.json +15 -0
- package/{configs → ide/configs}/gemini-cli-mcp.json +2 -2
- package/{configs → ide/configs}/jetbrains-mcp.json +2 -2
- package/{configs → ide/configs}/opencode-mcp.json +2 -2
- package/{configs → ide/configs}/perplexity-mcp.json +2 -2
- package/{configs → ide/configs}/vscode-copilot-mcp.json +2 -2
- package/{configs → ide/configs}/windsurf-mcp.json +3 -3
- package/{configs → ide/configs}/zed-mcp.json +2 -2
- package/{hooks → ide/hooks}/context-hook.js +9 -20
- package/ide/hooks/memory-list-skill.js +70 -0
- package/ide/hooks/memory-profile-skill.js +101 -0
- package/ide/hooks/memory-recall-skill.js +62 -0
- package/ide/hooks/memory-remember-skill.js +68 -0
- package/ide/hooks/memory-reset-skill.js +160 -0
- package/{hooks → ide/hooks}/post-recall-hook.js +2 -2
- package/ide/integrations/langchain/README.md +106 -0
- package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +9 -0
- package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +201 -0
- package/ide/integrations/langchain/pyproject.toml +38 -0
- package/{src/learning → ide/integrations/langchain}/tests/__init__.py +1 -0
- package/ide/integrations/langchain/tests/test_chat_message_history.py +215 -0
- package/ide/integrations/langchain/tests/test_security.py +117 -0
- package/ide/integrations/llamaindex/README.md +81 -0
- package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +9 -0
- package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +316 -0
- package/ide/integrations/llamaindex/pyproject.toml +43 -0
- package/{src/lifecycle → ide/integrations/llamaindex}/tests/__init__.py +1 -2
- package/ide/integrations/llamaindex/tests/test_chat_store.py +294 -0
- package/ide/integrations/llamaindex/tests/test_security.py +241 -0
- package/{skills → ide/skills}/slm-build-graph/SKILL.md +6 -6
- package/{skills → ide/skills}/slm-list-recent/SKILL.md +5 -5
- package/{skills → ide/skills}/slm-recall/SKILL.md +5 -5
- package/{skills → ide/skills}/slm-remember/SKILL.md +6 -6
- package/{skills → ide/skills}/slm-show-patterns/SKILL.md +7 -7
- package/{skills → ide/skills}/slm-status/SKILL.md +9 -9
- package/{skills → ide/skills}/slm-switch-profile/SKILL.md +9 -9
- package/package.json +13 -22
- package/pyproject.toml +85 -0
- package/scripts/build-dmg.sh +417 -0
- package/scripts/install-skills.ps1 +334 -0
- package/scripts/postinstall.js +2 -2
- package/scripts/start-dashboard.ps1 +52 -0
- package/scripts/start-dashboard.sh +41 -0
- package/scripts/sync-wiki.ps1 +127 -0
- package/scripts/sync-wiki.sh +82 -0
- package/scripts/test-dmg.sh +161 -0
- package/scripts/test-npm-package.ps1 +252 -0
- package/scripts/test-npm-package.sh +207 -0
- package/scripts/verify-install.ps1 +294 -0
- package/scripts/verify-install.sh +266 -0
- package/src/superlocalmemory/__init__.py +0 -0
- package/src/superlocalmemory/attribution/__init__.py +9 -0
- package/src/superlocalmemory/attribution/mathematical_dna.py +235 -0
- package/src/superlocalmemory/attribution/signer.py +153 -0
- package/src/superlocalmemory/attribution/watermark.py +189 -0
- package/src/superlocalmemory/cli/__init__.py +5 -0
- package/src/superlocalmemory/cli/commands.py +245 -0
- package/src/superlocalmemory/cli/main.py +89 -0
- package/src/superlocalmemory/cli/migrate_cmd.py +55 -0
- package/src/superlocalmemory/cli/post_install.py +99 -0
- package/src/superlocalmemory/cli/setup_wizard.py +129 -0
- package/src/superlocalmemory/compliance/__init__.py +0 -0
- package/src/superlocalmemory/compliance/abac.py +204 -0
- package/src/superlocalmemory/compliance/audit.py +314 -0
- package/src/superlocalmemory/compliance/eu_ai_act.py +131 -0
- package/src/superlocalmemory/compliance/gdpr.py +294 -0
- package/src/superlocalmemory/compliance/lifecycle.py +158 -0
- package/src/superlocalmemory/compliance/retention.py +232 -0
- package/src/superlocalmemory/compliance/scheduler.py +148 -0
- package/src/superlocalmemory/core/__init__.py +0 -0
- package/src/superlocalmemory/core/config.py +391 -0
- package/src/superlocalmemory/core/embeddings.py +293 -0
- package/src/superlocalmemory/core/engine.py +701 -0
- package/src/superlocalmemory/core/hooks.py +65 -0
- package/src/superlocalmemory/core/maintenance.py +172 -0
- package/src/superlocalmemory/core/modes.py +140 -0
- package/src/superlocalmemory/core/profiles.py +234 -0
- package/src/superlocalmemory/core/registry.py +117 -0
- package/src/superlocalmemory/dynamics/__init__.py +0 -0
- package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +223 -0
- package/src/superlocalmemory/encoding/__init__.py +0 -0
- package/src/superlocalmemory/encoding/consolidator.py +485 -0
- package/src/superlocalmemory/encoding/emotional.py +125 -0
- package/src/superlocalmemory/encoding/entity_resolver.py +525 -0
- package/src/superlocalmemory/encoding/entropy_gate.py +104 -0
- package/src/superlocalmemory/encoding/fact_extractor.py +775 -0
- package/src/superlocalmemory/encoding/foresight.py +91 -0
- package/src/superlocalmemory/encoding/graph_builder.py +302 -0
- package/src/superlocalmemory/encoding/observation_builder.py +160 -0
- package/src/superlocalmemory/encoding/scene_builder.py +183 -0
- package/src/superlocalmemory/encoding/signal_inference.py +90 -0
- package/src/superlocalmemory/encoding/temporal_parser.py +426 -0
- package/src/superlocalmemory/encoding/type_router.py +235 -0
- package/src/superlocalmemory/hooks/__init__.py +3 -0
- package/src/superlocalmemory/hooks/auto_capture.py +111 -0
- package/src/superlocalmemory/hooks/auto_recall.py +93 -0
- package/src/superlocalmemory/hooks/ide_connector.py +204 -0
- package/src/superlocalmemory/hooks/rules_engine.py +99 -0
- package/src/superlocalmemory/infra/__init__.py +3 -0
- package/src/superlocalmemory/infra/auth_middleware.py +82 -0
- package/src/superlocalmemory/infra/backup.py +317 -0
- package/src/superlocalmemory/infra/cache_manager.py +267 -0
- package/src/superlocalmemory/infra/event_bus.py +381 -0
- package/src/superlocalmemory/infra/rate_limiter.py +135 -0
- package/src/{webhook_dispatcher.py → superlocalmemory/infra/webhook_dispatcher.py} +104 -101
- package/src/superlocalmemory/learning/__init__.py +0 -0
- package/src/superlocalmemory/learning/adaptive.py +172 -0
- package/src/superlocalmemory/learning/behavioral.py +490 -0
- package/src/superlocalmemory/learning/behavioral_listener.py +94 -0
- package/src/superlocalmemory/learning/bootstrap.py +298 -0
- package/src/superlocalmemory/learning/cross_project.py +399 -0
- package/src/superlocalmemory/learning/database.py +376 -0
- package/src/superlocalmemory/learning/engagement.py +323 -0
- package/src/superlocalmemory/learning/features.py +138 -0
- package/src/superlocalmemory/learning/feedback.py +316 -0
- package/src/superlocalmemory/learning/outcomes.py +255 -0
- package/src/superlocalmemory/learning/project_context.py +366 -0
- package/src/superlocalmemory/learning/ranker.py +155 -0
- package/src/superlocalmemory/learning/source_quality.py +303 -0
- package/src/superlocalmemory/learning/workflows.py +309 -0
- package/src/superlocalmemory/llm/__init__.py +0 -0
- package/src/superlocalmemory/llm/backbone.py +316 -0
- package/src/superlocalmemory/math/__init__.py +0 -0
- package/src/superlocalmemory/math/fisher.py +356 -0
- package/src/superlocalmemory/math/langevin.py +398 -0
- package/src/superlocalmemory/math/sheaf.py +257 -0
- package/src/superlocalmemory/mcp/__init__.py +0 -0
- package/src/superlocalmemory/mcp/resources.py +245 -0
- package/src/superlocalmemory/mcp/server.py +61 -0
- package/src/superlocalmemory/mcp/tools.py +18 -0
- package/src/superlocalmemory/mcp/tools_core.py +305 -0
- package/src/superlocalmemory/mcp/tools_v28.py +223 -0
- package/src/superlocalmemory/mcp/tools_v3.py +286 -0
- package/src/superlocalmemory/retrieval/__init__.py +0 -0
- package/src/superlocalmemory/retrieval/agentic.py +295 -0
- package/src/superlocalmemory/retrieval/ann_index.py +223 -0
- package/src/superlocalmemory/retrieval/bm25_channel.py +185 -0
- package/src/superlocalmemory/retrieval/bridge_discovery.py +170 -0
- package/src/superlocalmemory/retrieval/engine.py +390 -0
- package/src/superlocalmemory/retrieval/entity_channel.py +179 -0
- package/src/superlocalmemory/retrieval/fusion.py +78 -0
- package/src/superlocalmemory/retrieval/profile_channel.py +105 -0
- package/src/superlocalmemory/retrieval/reranker.py +154 -0
- package/src/superlocalmemory/retrieval/semantic_channel.py +232 -0
- package/src/superlocalmemory/retrieval/strategy.py +96 -0
- package/src/superlocalmemory/retrieval/temporal_channel.py +175 -0
- package/src/superlocalmemory/server/__init__.py +1 -0
- package/src/superlocalmemory/server/api.py +248 -0
- package/src/superlocalmemory/server/routes/__init__.py +4 -0
- package/src/superlocalmemory/server/routes/agents.py +107 -0
- package/src/superlocalmemory/server/routes/backup.py +91 -0
- package/src/superlocalmemory/server/routes/behavioral.py +127 -0
- package/src/superlocalmemory/server/routes/compliance.py +160 -0
- package/src/superlocalmemory/server/routes/data_io.py +188 -0
- package/src/superlocalmemory/server/routes/events.py +183 -0
- package/src/superlocalmemory/server/routes/helpers.py +85 -0
- package/src/superlocalmemory/server/routes/learning.py +273 -0
- package/src/superlocalmemory/server/routes/lifecycle.py +116 -0
- package/src/superlocalmemory/server/routes/memories.py +399 -0
- package/src/superlocalmemory/server/routes/profiles.py +219 -0
- package/src/superlocalmemory/server/routes/stats.py +346 -0
- package/src/superlocalmemory/server/routes/v3_api.py +365 -0
- package/src/superlocalmemory/server/routes/ws.py +82 -0
- package/src/superlocalmemory/server/security_middleware.py +57 -0
- package/src/superlocalmemory/server/ui.py +245 -0
- package/src/superlocalmemory/storage/__init__.py +0 -0
- package/src/superlocalmemory/storage/access_control.py +182 -0
- package/src/superlocalmemory/storage/database.py +594 -0
- package/src/superlocalmemory/storage/migrations.py +303 -0
- package/src/superlocalmemory/storage/models.py +406 -0
- package/src/superlocalmemory/storage/schema.py +726 -0
- package/src/superlocalmemory/storage/v2_migrator.py +317 -0
- package/src/superlocalmemory/trust/__init__.py +0 -0
- package/src/superlocalmemory/trust/gate.py +130 -0
- package/src/superlocalmemory/trust/provenance.py +124 -0
- package/src/superlocalmemory/trust/scorer.py +347 -0
- package/src/superlocalmemory/trust/signals.py +153 -0
- package/ui/index.html +278 -5
- package/ui/js/auto-settings.js +70 -0
- package/ui/js/dashboard.js +90 -0
- package/ui/js/fact-detail.js +92 -0
- package/ui/js/feedback.js +2 -2
- package/ui/js/ide-status.js +102 -0
- package/ui/js/math-health.js +98 -0
- package/ui/js/recall-lab.js +127 -0
- package/ui/js/settings.js +2 -2
- package/ui/js/trust-dashboard.js +73 -0
- package/api_server.py +0 -724
- package/bin/aider-smart +0 -72
- package/bin/superlocalmemoryv2-learning +0 -4
- package/bin/superlocalmemoryv2-list +0 -3
- package/bin/superlocalmemoryv2-patterns +0 -4
- package/bin/superlocalmemoryv2-profile +0 -3
- package/bin/superlocalmemoryv2-recall +0 -3
- package/bin/superlocalmemoryv2-remember +0 -3
- package/bin/superlocalmemoryv2-reset +0 -3
- package/bin/superlocalmemoryv2-status +0 -3
- package/configs/chatgpt-desktop-mcp.json +0 -16
- package/configs/cursor-mcp.json +0 -15
- package/hooks/memory-list-skill.js +0 -139
- package/hooks/memory-profile-skill.js +0 -273
- package/hooks/memory-recall-skill.js +0 -114
- package/hooks/memory-remember-skill.js +0 -127
- package/hooks/memory-reset-skill.js +0 -274
- package/mcp_server.py +0 -1808
- package/requirements-core.txt +0 -22
- package/requirements-learning.txt +0 -12
- package/requirements.txt +0 -12
- package/src/agent_registry.py +0 -411
- package/src/auth_middleware.py +0 -61
- package/src/auto_backup.py +0 -459
- package/src/behavioral/__init__.py +0 -49
- package/src/behavioral/behavioral_listener.py +0 -203
- package/src/behavioral/behavioral_patterns.py +0 -275
- package/src/behavioral/cross_project_transfer.py +0 -206
- package/src/behavioral/outcome_inference.py +0 -194
- package/src/behavioral/outcome_tracker.py +0 -193
- package/src/behavioral/tests/__init__.py +0 -4
- package/src/behavioral/tests/test_behavioral_integration.py +0 -108
- package/src/behavioral/tests/test_behavioral_patterns.py +0 -150
- package/src/behavioral/tests/test_cross_project_transfer.py +0 -142
- package/src/behavioral/tests/test_mcp_behavioral.py +0 -139
- package/src/behavioral/tests/test_mcp_report_outcome.py +0 -117
- package/src/behavioral/tests/test_outcome_inference.py +0 -107
- package/src/behavioral/tests/test_outcome_tracker.py +0 -96
- package/src/cache_manager.py +0 -518
- package/src/compliance/__init__.py +0 -48
- package/src/compliance/abac_engine.py +0 -149
- package/src/compliance/abac_middleware.py +0 -116
- package/src/compliance/audit_db.py +0 -215
- package/src/compliance/audit_logger.py +0 -148
- package/src/compliance/retention_manager.py +0 -289
- package/src/compliance/retention_scheduler.py +0 -186
- package/src/compliance/tests/__init__.py +0 -4
- package/src/compliance/tests/test_abac_enforcement.py +0 -95
- package/src/compliance/tests/test_abac_engine.py +0 -124
- package/src/compliance/tests/test_abac_mcp_integration.py +0 -118
- package/src/compliance/tests/test_audit_db.py +0 -123
- package/src/compliance/tests/test_audit_logger.py +0 -98
- package/src/compliance/tests/test_mcp_audit.py +0 -128
- package/src/compliance/tests/test_mcp_retention_policy.py +0 -125
- package/src/compliance/tests/test_retention_manager.py +0 -131
- package/src/compliance/tests/test_retention_scheduler.py +0 -99
- package/src/compression/__init__.py +0 -25
- package/src/compression/cli.py +0 -150
- package/src/compression/cold_storage.py +0 -217
- package/src/compression/config.py +0 -72
- package/src/compression/orchestrator.py +0 -133
- package/src/compression/tier2_compressor.py +0 -228
- package/src/compression/tier3_compressor.py +0 -153
- package/src/compression/tier_classifier.py +0 -148
- package/src/db_connection_manager.py +0 -536
- package/src/embedding_engine.py +0 -63
- package/src/embeddings/__init__.py +0 -47
- package/src/embeddings/cache.py +0 -70
- package/src/embeddings/cli.py +0 -113
- package/src/embeddings/constants.py +0 -47
- package/src/embeddings/database.py +0 -91
- package/src/embeddings/engine.py +0 -247
- package/src/embeddings/model_loader.py +0 -145
- package/src/event_bus.py +0 -562
- package/src/graph/__init__.py +0 -36
- package/src/graph/build_helpers.py +0 -74
- package/src/graph/cli.py +0 -87
- package/src/graph/cluster_builder.py +0 -188
- package/src/graph/cluster_summary.py +0 -148
- package/src/graph/constants.py +0 -47
- package/src/graph/edge_builder.py +0 -162
- package/src/graph/entity_extractor.py +0 -95
- package/src/graph/graph_core.py +0 -226
- package/src/graph/graph_search.py +0 -231
- package/src/graph/hierarchical.py +0 -207
- package/src/graph/schema.py +0 -99
- package/src/graph_engine.py +0 -52
- package/src/hnsw_index.py +0 -628
- package/src/hybrid_search.py +0 -46
- package/src/learning/__init__.py +0 -217
- package/src/learning/adaptive_ranker.py +0 -682
- package/src/learning/bootstrap/__init__.py +0 -69
- package/src/learning/bootstrap/constants.py +0 -93
- package/src/learning/bootstrap/db_queries.py +0 -316
- package/src/learning/bootstrap/sampling.py +0 -82
- package/src/learning/bootstrap/text_utils.py +0 -71
- package/src/learning/cross_project_aggregator.py +0 -857
- package/src/learning/db/__init__.py +0 -40
- package/src/learning/db/constants.py +0 -44
- package/src/learning/db/schema.py +0 -279
- package/src/learning/engagement_tracker.py +0 -628
- package/src/learning/feature_extractor.py +0 -708
- package/src/learning/feedback_collector.py +0 -806
- package/src/learning/learning_db.py +0 -915
- package/src/learning/project_context_manager.py +0 -572
- package/src/learning/ranking/__init__.py +0 -33
- package/src/learning/ranking/constants.py +0 -84
- package/src/learning/ranking/helpers.py +0 -278
- package/src/learning/source_quality_scorer.py +0 -676
- package/src/learning/synthetic_bootstrap.py +0 -755
- package/src/learning/tests/test_adaptive_ranker.py +0 -325
- package/src/learning/tests/test_adaptive_ranker_v28.py +0 -60
- package/src/learning/tests/test_aggregator.py +0 -306
- package/src/learning/tests/test_auto_retrain_v28.py +0 -35
- package/src/learning/tests/test_e2e_ranking_v28.py +0 -82
- package/src/learning/tests/test_feature_extractor_v28.py +0 -93
- package/src/learning/tests/test_feedback_collector.py +0 -294
- package/src/learning/tests/test_learning_db.py +0 -602
- package/src/learning/tests/test_learning_db_v28.py +0 -110
- package/src/learning/tests/test_learning_init_v28.py +0 -48
- package/src/learning/tests/test_outcome_signals.py +0 -48
- package/src/learning/tests/test_project_context.py +0 -292
- package/src/learning/tests/test_schema_migration.py +0 -319
- package/src/learning/tests/test_signal_inference.py +0 -397
- package/src/learning/tests/test_source_quality.py +0 -351
- package/src/learning/tests/test_synthetic_bootstrap.py +0 -429
- package/src/learning/tests/test_workflow_miner.py +0 -318
- package/src/learning/workflow_pattern_miner.py +0 -655
- package/src/lifecycle/__init__.py +0 -54
- package/src/lifecycle/bounded_growth.py +0 -239
- package/src/lifecycle/compaction_engine.py +0 -226
- package/src/lifecycle/lifecycle_engine.py +0 -355
- package/src/lifecycle/lifecycle_evaluator.py +0 -257
- package/src/lifecycle/lifecycle_scheduler.py +0 -130
- package/src/lifecycle/retention_policy.py +0 -285
- package/src/lifecycle/tests/test_bounded_growth.py +0 -193
- package/src/lifecycle/tests/test_compaction.py +0 -179
- package/src/lifecycle/tests/test_lifecycle_engine.py +0 -137
- package/src/lifecycle/tests/test_lifecycle_evaluation.py +0 -177
- package/src/lifecycle/tests/test_lifecycle_scheduler.py +0 -127
- package/src/lifecycle/tests/test_lifecycle_search.py +0 -109
- package/src/lifecycle/tests/test_mcp_compact.py +0 -149
- package/src/lifecycle/tests/test_mcp_lifecycle_status.py +0 -114
- package/src/lifecycle/tests/test_retention_policy.py +0 -162
- package/src/mcp_tools_v28.py +0 -281
- package/src/memory/__init__.py +0 -36
- package/src/memory/cli.py +0 -205
- package/src/memory/constants.py +0 -39
- package/src/memory/helpers.py +0 -28
- package/src/memory/schema.py +0 -166
- package/src/memory-profiles.py +0 -595
- package/src/memory-reset.py +0 -491
- package/src/memory_compression.py +0 -989
- package/src/memory_store_v2.py +0 -1155
- package/src/migrate_v1_to_v2.py +0 -629
- package/src/pattern_learner.py +0 -34
- package/src/patterns/__init__.py +0 -24
- package/src/patterns/analyzers.py +0 -251
- package/src/patterns/learner.py +0 -271
- package/src/patterns/scoring.py +0 -171
- package/src/patterns/store.py +0 -225
- package/src/patterns/terminology.py +0 -140
- package/src/provenance_tracker.py +0 -312
- package/src/qualixar_attribution.py +0 -139
- package/src/qualixar_watermark.py +0 -78
- package/src/query_optimizer.py +0 -511
- package/src/rate_limiter.py +0 -83
- package/src/search/__init__.py +0 -20
- package/src/search/cli.py +0 -77
- package/src/search/constants.py +0 -26
- package/src/search/engine.py +0 -241
- package/src/search/fusion.py +0 -122
- package/src/search/index_loader.py +0 -114
- package/src/search/methods.py +0 -162
- package/src/search_engine_v2.py +0 -401
- package/src/setup_validator.py +0 -482
- package/src/subscription_manager.py +0 -391
- package/src/tree/__init__.py +0 -59
- package/src/tree/builder.py +0 -185
- package/src/tree/nodes.py +0 -202
- package/src/tree/queries.py +0 -257
- package/src/tree/schema.py +0 -80
- package/src/tree_manager.py +0 -19
- package/src/trust/__init__.py +0 -45
- package/src/trust/constants.py +0 -66
- package/src/trust/queries.py +0 -157
- package/src/trust/schema.py +0 -95
- package/src/trust/scorer.py +0 -299
- package/src/trust/signals.py +0 -95
- package/src/trust_scorer.py +0 -44
- package/ui/app.js +0 -1588
- package/ui/js/graph-cytoscape-monolithic-backup.js +0 -1168
- package/ui/js/graph-cytoscape.js +0 -1168
- package/ui/js/graph-d3-backup.js +0 -32
- package/ui/js/graph.js +0 -32
- package/ui_server.py +0 -286
- /package/docs/{ACCESSIBILITY.md → v2-archive/ACCESSIBILITY.md} +0 -0
- /package/docs/{ARCHITECTURE.md → v2-archive/ARCHITECTURE.md} +0 -0
- /package/docs/{CLI-COMMANDS-REFERENCE.md → v2-archive/CLI-COMMANDS-REFERENCE.md} +0 -0
- /package/docs/{COMPRESSION-README.md → v2-archive/COMPRESSION-README.md} +0 -0
- /package/docs/{FRAMEWORK-INTEGRATIONS.md → v2-archive/FRAMEWORK-INTEGRATIONS.md} +0 -0
- /package/docs/{MCP-MANUAL-SETUP.md → v2-archive/MCP-MANUAL-SETUP.md} +0 -0
- /package/docs/{MCP-TROUBLESHOOTING.md → v2-archive/MCP-TROUBLESHOOTING.md} +0 -0
- /package/docs/{PATTERN-LEARNING.md → v2-archive/PATTERN-LEARNING.md} +0 -0
- /package/docs/{PROFILES-GUIDE.md → v2-archive/PROFILES-GUIDE.md} +0 -0
- /package/docs/{RESET-GUIDE.md → v2-archive/RESET-GUIDE.md} +0 -0
- /package/docs/{SEARCH-ENGINE-V2.2.0.md → v2-archive/SEARCH-ENGINE-V2.2.0.md} +0 -0
- /package/docs/{SEARCH-INTEGRATION-GUIDE.md → v2-archive/SEARCH-INTEGRATION-GUIDE.md} +0 -0
- /package/docs/{UI-SERVER.md → v2-archive/UI-SERVER.md} +0 -0
- /package/docs/{UNIVERSAL-INTEGRATION.md → v2-archive/UNIVERSAL-INTEGRATION.md} +0 -0
- /package/docs/{V2.2.0-OPTIONAL-SEARCH.md → v2-archive/V2.2.0-OPTIONAL-SEARCH.md} +0 -0
- /package/docs/{WINDOWS-INSTALL-README.txt → v2-archive/WINDOWS-INSTALL-README.txt} +0 -0
- /package/docs/{WINDOWS-POST-INSTALL.txt → v2-archive/WINDOWS-POST-INSTALL.txt} +0 -0
- /package/docs/{example_graph_usage.py → v2-archive/example_graph_usage.py} +0 -0
- /package/{completions → ide/completions}/slm.bash +0 -0
- /package/{completions → ide/completions}/slm.zsh +0 -0
- /package/{configs → ide/configs}/cody-commands.json +0 -0
- /package/{install-skills.sh → scripts/install-skills.sh} +0 -0
- /package/{install.ps1 → scripts/install.ps1} +0 -0
- /package/{install.sh → scripts/install.sh} +0 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
3
|
+
# Licensed under the MIT License - see LICENSE file
|
|
4
|
+
# Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
|
|
5
|
+
"""
|
|
6
|
+
SuperLocalMemory V3 - FastAPI API Server
|
|
7
|
+
Provides REST endpoints for memory visualization and exploration.
|
|
8
|
+
Uses V3 MemoryEngine for all operations.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import logging
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from contextlib import asynccontextmanager
|
|
15
|
+
from typing import Optional
|
|
16
|
+
|
|
17
|
+
from fastapi import FastAPI, HTTPException, Query, Request
|
|
18
|
+
from fastapi.staticfiles import StaticFiles
|
|
19
|
+
from fastapi.responses import HTMLResponse
|
|
20
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
21
|
+
from fastapi.middleware.gzip import GZipMiddleware
|
|
22
|
+
from pydantic import BaseModel
|
|
23
|
+
import uvicorn
|
|
24
|
+
|
|
25
|
+
from superlocalmemory.server.security_middleware import SecurityHeadersMiddleware
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger("superlocalmemory.api_server")
|
|
28
|
+
|
|
29
|
+
# V3 paths
|
|
30
|
+
MEMORY_DIR = Path.home() / ".superlocalmemory"
|
|
31
|
+
DB_PATH = MEMORY_DIR / "memory.db"
|
|
32
|
+
# ui/ is at repo root, 4 levels up from src/superlocalmemory/server/api.py
|
|
33
|
+
UI_DIR = Path(__file__).resolve().parent.parent.parent.parent / "ui"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ============================================================================
|
|
37
|
+
# Request/Response Models
|
|
38
|
+
# ============================================================================
|
|
39
|
+
|
|
40
|
+
class SearchRequest(BaseModel):
|
|
41
|
+
query: str
|
|
42
|
+
limit: int = 10
|
|
43
|
+
min_score: float = 0.3
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class MemoryFilter(BaseModel):
|
|
47
|
+
category: Optional[str] = None
|
|
48
|
+
project_name: Optional[str] = None
|
|
49
|
+
cluster_id: Optional[int] = None
|
|
50
|
+
min_importance: Optional[int] = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# ============================================================================
|
|
54
|
+
# V3 Engine Initialization (lifespan context)
|
|
55
|
+
# ============================================================================
|
|
56
|
+
|
|
57
|
+
@asynccontextmanager
|
|
58
|
+
async def lifespan(application: FastAPI):
|
|
59
|
+
"""Initialize V3 engine on startup, cleanup on shutdown."""
|
|
60
|
+
try:
|
|
61
|
+
from superlocalmemory.core.config import SLMConfig
|
|
62
|
+
from superlocalmemory.core.engine import MemoryEngine
|
|
63
|
+
|
|
64
|
+
config = SLMConfig.load()
|
|
65
|
+
engine = MemoryEngine(config)
|
|
66
|
+
engine.initialize()
|
|
67
|
+
application.state.engine = engine
|
|
68
|
+
application.state.config = config
|
|
69
|
+
logger.info("V3 MemoryEngine initialized: mode=%s", config.mode.value)
|
|
70
|
+
except Exception as exc:
|
|
71
|
+
logger.warning("V3 engine init failed (API will use fallback): %s", exc)
|
|
72
|
+
application.state.engine = None
|
|
73
|
+
application.state.config = None
|
|
74
|
+
|
|
75
|
+
yield
|
|
76
|
+
|
|
77
|
+
# Cleanup
|
|
78
|
+
if hasattr(application.state, 'engine') and application.state.engine:
|
|
79
|
+
application.state.engine.close()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def create_app() -> FastAPI:
|
|
83
|
+
"""Create and configure the FastAPI application."""
|
|
84
|
+
application = FastAPI(
|
|
85
|
+
title="SuperLocalMemory V3 API",
|
|
86
|
+
description="V3 Memory Engine REST API",
|
|
87
|
+
version="3.0.0",
|
|
88
|
+
lifespan=lifespan,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Middleware
|
|
92
|
+
application.add_middleware(SecurityHeadersMiddleware)
|
|
93
|
+
application.add_middleware(GZipMiddleware, minimum_size=1000)
|
|
94
|
+
application.add_middleware(
|
|
95
|
+
CORSMiddleware,
|
|
96
|
+
allow_origins=[
|
|
97
|
+
"http://localhost:8765", "http://127.0.0.1:8765",
|
|
98
|
+
"http://localhost:8417", "http://127.0.0.1:8417",
|
|
99
|
+
],
|
|
100
|
+
allow_credentials=True,
|
|
101
|
+
allow_methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
|
|
102
|
+
allow_headers=["Content-Type", "Authorization", "X-SLM-API-Key"],
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Rate limiting (graceful)
|
|
106
|
+
try:
|
|
107
|
+
from superlocalmemory.infra.rate_limiter import RateLimiter
|
|
108
|
+
_write_limiter = RateLimiter(max_requests=30, window_seconds=60)
|
|
109
|
+
_read_limiter = RateLimiter(max_requests=120, window_seconds=60)
|
|
110
|
+
|
|
111
|
+
@application.middleware("http")
|
|
112
|
+
async def rate_limit_middleware(request, call_next):
|
|
113
|
+
client_ip = request.client.host if request.client else "unknown"
|
|
114
|
+
is_write = request.method in ("POST", "PUT", "DELETE", "PATCH")
|
|
115
|
+
limiter = _write_limiter if is_write else _read_limiter
|
|
116
|
+
allowed, remaining = limiter.is_allowed(client_ip)
|
|
117
|
+
if not allowed:
|
|
118
|
+
from fastapi.responses import JSONResponse
|
|
119
|
+
return JSONResponse(
|
|
120
|
+
status_code=429,
|
|
121
|
+
content={"error": "Too many requests."},
|
|
122
|
+
headers={"Retry-After": str(limiter.window_seconds)},
|
|
123
|
+
)
|
|
124
|
+
response = await call_next(request)
|
|
125
|
+
response.headers["X-RateLimit-Remaining"] = str(remaining)
|
|
126
|
+
return response
|
|
127
|
+
except (ImportError, Exception):
|
|
128
|
+
pass
|
|
129
|
+
|
|
130
|
+
# Auth middleware (graceful)
|
|
131
|
+
try:
|
|
132
|
+
from superlocalmemory.infra.auth_middleware import check_api_key
|
|
133
|
+
|
|
134
|
+
@application.middleware("http")
|
|
135
|
+
async def auth_middleware(request, call_next):
|
|
136
|
+
is_write = request.method in ("POST", "PUT", "DELETE", "PATCH")
|
|
137
|
+
headers = dict(request.headers)
|
|
138
|
+
if not check_api_key(headers, is_write=is_write):
|
|
139
|
+
from fastapi.responses import JSONResponse
|
|
140
|
+
return JSONResponse(
|
|
141
|
+
status_code=401,
|
|
142
|
+
content={"error": "Invalid or missing API key."},
|
|
143
|
+
)
|
|
144
|
+
response = await call_next(request)
|
|
145
|
+
return response
|
|
146
|
+
except (ImportError, Exception):
|
|
147
|
+
pass
|
|
148
|
+
|
|
149
|
+
# Mount static files
|
|
150
|
+
UI_DIR.mkdir(exist_ok=True)
|
|
151
|
+
application.mount("/static", StaticFiles(directory=str(UI_DIR)), name="static")
|
|
152
|
+
|
|
153
|
+
# ========================================================================
|
|
154
|
+
# Register Route Modules
|
|
155
|
+
# ========================================================================
|
|
156
|
+
from superlocalmemory.server.routes.memories import router as memories_router
|
|
157
|
+
from superlocalmemory.server.routes.stats import router as stats_router
|
|
158
|
+
from superlocalmemory.server.routes.profiles import router as profiles_router
|
|
159
|
+
from superlocalmemory.server.routes.backup import router as backup_router
|
|
160
|
+
from superlocalmemory.server.routes.data_io import router as data_io_router
|
|
161
|
+
from superlocalmemory.server.routes.events import router as events_router, register_event_listener
|
|
162
|
+
from superlocalmemory.server.routes.agents import router as agents_router
|
|
163
|
+
from superlocalmemory.server.routes.ws import router as ws_router, manager as ws_manager
|
|
164
|
+
from superlocalmemory.server.routes.v3_api import router as v3_router
|
|
165
|
+
|
|
166
|
+
application.include_router(memories_router)
|
|
167
|
+
application.include_router(stats_router)
|
|
168
|
+
application.include_router(profiles_router)
|
|
169
|
+
application.include_router(backup_router)
|
|
170
|
+
application.include_router(data_io_router)
|
|
171
|
+
application.include_router(events_router)
|
|
172
|
+
application.include_router(agents_router)
|
|
173
|
+
application.include_router(ws_router)
|
|
174
|
+
application.include_router(v3_router)
|
|
175
|
+
|
|
176
|
+
# Graceful optional routers
|
|
177
|
+
for _module_name in ("learning", "lifecycle", "behavioral", "compliance"):
|
|
178
|
+
try:
|
|
179
|
+
_mod = __import__(f"superlocalmemory.server.routes.{_module_name}", fromlist=["router"])
|
|
180
|
+
application.include_router(_mod.router)
|
|
181
|
+
except (ImportError, Exception):
|
|
182
|
+
pass
|
|
183
|
+
|
|
184
|
+
# Wire WebSocket manager
|
|
185
|
+
import superlocalmemory.server.routes.profiles as _profiles_mod
|
|
186
|
+
import superlocalmemory.server.routes.data_io as _data_io_mod
|
|
187
|
+
_profiles_mod.ws_manager = ws_manager
|
|
188
|
+
_data_io_mod.ws_manager = ws_manager
|
|
189
|
+
|
|
190
|
+
# ========================================================================
|
|
191
|
+
# Basic Routes
|
|
192
|
+
# ========================================================================
|
|
193
|
+
|
|
194
|
+
@application.get("/", response_class=HTMLResponse)
|
|
195
|
+
async def root():
|
|
196
|
+
"""Serve main UI page."""
|
|
197
|
+
index_path = UI_DIR / "index.html"
|
|
198
|
+
if not index_path.exists():
|
|
199
|
+
return (
|
|
200
|
+
"<html><head><title>SuperLocalMemory V3</title></head>"
|
|
201
|
+
"<body style='font-family:Arial;padding:40px'>"
|
|
202
|
+
"<h1>SuperLocalMemory V3 API Server Running</h1>"
|
|
203
|
+
"<p><a href='/docs'>API Documentation</a></p>"
|
|
204
|
+
"</body></html>"
|
|
205
|
+
)
|
|
206
|
+
return index_path.read_text()
|
|
207
|
+
|
|
208
|
+
@application.get("/health")
|
|
209
|
+
async def health_check():
|
|
210
|
+
"""Health check."""
|
|
211
|
+
from datetime import datetime
|
|
212
|
+
engine = application.state.engine
|
|
213
|
+
return {
|
|
214
|
+
"status": "healthy",
|
|
215
|
+
"version": "3.0.0",
|
|
216
|
+
"engine": "initialized" if engine else "unavailable",
|
|
217
|
+
"database": "connected" if DB_PATH.exists() else "missing",
|
|
218
|
+
"timestamp": datetime.now().isoformat(),
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
@application.on_event("startup")
|
|
222
|
+
async def startup_event():
|
|
223
|
+
register_event_listener()
|
|
224
|
+
|
|
225
|
+
return application
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
app = create_app()
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
# ============================================================================
|
|
232
|
+
# Server Startup
|
|
233
|
+
# ============================================================================
|
|
234
|
+
|
|
235
|
+
if __name__ == "__main__":
|
|
236
|
+
print("=" * 60)
|
|
237
|
+
print("SuperLocalMemory V3 - API Server")
|
|
238
|
+
print("=" * 60)
|
|
239
|
+
print(f"Database: {DB_PATH}")
|
|
240
|
+
print(f"UI Directory: {UI_DIR}")
|
|
241
|
+
print("=" * 60)
|
|
242
|
+
print("\nStarting server on http://localhost:8000")
|
|
243
|
+
print("API Documentation: http://localhost:8000/docs")
|
|
244
|
+
print("\nPress Ctrl+C to stop\n")
|
|
245
|
+
|
|
246
|
+
uvicorn.run(
|
|
247
|
+
app, host="127.0.0.1", port=8000, log_level="info",
|
|
248
|
+
)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under the MIT License - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
|
|
4
|
+
"""SuperLocalMemory V3 - Agent Registry + Trust Routes
|
|
5
|
+
- MIT License
|
|
6
|
+
|
|
7
|
+
Routes: /api/agents, /api/agents/stats, /api/trust/stats, /api/trust/signals/{agent_id}
|
|
8
|
+
Uses V3 TrustScorer and core.registry.
|
|
9
|
+
"""
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Optional
|
|
12
|
+
|
|
13
|
+
from fastapi import APIRouter, HTTPException, Query, Request
|
|
14
|
+
|
|
15
|
+
from .helpers import DB_PATH
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger("superlocalmemory.routes.agents")
|
|
18
|
+
router = APIRouter()
|
|
19
|
+
|
|
20
|
+
# Feature flag: V3 trust scorer
|
|
21
|
+
TRUST_AVAILABLE = False
|
|
22
|
+
try:
|
|
23
|
+
from superlocalmemory.trust.scorer import TrustScorer
|
|
24
|
+
TRUST_AVAILABLE = True
|
|
25
|
+
except ImportError:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
REGISTRY_AVAILABLE = False
|
|
29
|
+
try:
|
|
30
|
+
from superlocalmemory.core.registry import AgentRegistry
|
|
31
|
+
REGISTRY_AVAILABLE = True
|
|
32
|
+
except ImportError:
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@router.get("/api/agents")
|
|
37
|
+
async def get_agents(
|
|
38
|
+
request: Request,
|
|
39
|
+
protocol: Optional[str] = None,
|
|
40
|
+
limit: int = Query(50, ge=1, le=200),
|
|
41
|
+
):
|
|
42
|
+
"""List registered agents with optional protocol filter."""
|
|
43
|
+
if not REGISTRY_AVAILABLE:
|
|
44
|
+
return {"agents": [], "count": 0, "message": "Agent registry not available"}
|
|
45
|
+
try:
|
|
46
|
+
engine = getattr(request.app.state, "engine", None)
|
|
47
|
+
if engine and hasattr(engine, '_db'):
|
|
48
|
+
registry = AgentRegistry(engine._db)
|
|
49
|
+
agents = registry.list_agents(protocol=protocol, limit=limit)
|
|
50
|
+
stats = registry.get_stats()
|
|
51
|
+
return {"agents": agents, "count": len(agents), "stats": stats}
|
|
52
|
+
return {"agents": [], "count": 0, "message": "Engine not initialized"}
|
|
53
|
+
except Exception as e:
|
|
54
|
+
raise HTTPException(status_code=500, detail=f"Agent registry error: {str(e)}")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@router.get("/api/agents/stats")
|
|
58
|
+
async def get_agent_stats(request: Request):
|
|
59
|
+
"""Get agent registry statistics."""
|
|
60
|
+
if not REGISTRY_AVAILABLE:
|
|
61
|
+
return {"total_agents": 0, "message": "Agent registry not available"}
|
|
62
|
+
try:
|
|
63
|
+
engine = getattr(request.app.state, "engine", None)
|
|
64
|
+
if engine and hasattr(engine, '_db'):
|
|
65
|
+
registry = AgentRegistry(engine._db)
|
|
66
|
+
return registry.get_stats()
|
|
67
|
+
return {"total_agents": 0, "message": "Engine not initialized"}
|
|
68
|
+
except Exception as e:
|
|
69
|
+
raise HTTPException(status_code=500, detail=f"Agent stats error: {str(e)}")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@router.get("/api/trust/stats")
|
|
73
|
+
async def get_trust_stats(request: Request):
|
|
74
|
+
"""Get trust scoring statistics."""
|
|
75
|
+
if not TRUST_AVAILABLE:
|
|
76
|
+
return {"total_signals": 0, "message": "Trust scorer not available"}
|
|
77
|
+
try:
|
|
78
|
+
engine = getattr(request.app.state, "engine", None)
|
|
79
|
+
if engine and engine._trust_scorer:
|
|
80
|
+
scorer = engine._trust_scorer
|
|
81
|
+
return scorer.get_trust_stats()
|
|
82
|
+
return {"total_signals": 0, "message": "Trust scorer not initialized"}
|
|
83
|
+
except Exception as e:
|
|
84
|
+
raise HTTPException(status_code=500, detail=f"Trust stats error: {str(e)}")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@router.get("/api/trust/signals/{agent_id}")
|
|
88
|
+
async def get_agent_trust_signals(
|
|
89
|
+
request: Request, agent_id: str,
|
|
90
|
+
limit: int = Query(50, ge=1, le=200),
|
|
91
|
+
):
|
|
92
|
+
"""Get trust signal history for a specific agent."""
|
|
93
|
+
if not TRUST_AVAILABLE:
|
|
94
|
+
return {"signals": [], "count": 0}
|
|
95
|
+
try:
|
|
96
|
+
engine = getattr(request.app.state, "engine", None)
|
|
97
|
+
if engine and engine._trust_scorer:
|
|
98
|
+
scorer = engine._trust_scorer
|
|
99
|
+
signals = scorer.get_signals(agent_id, limit=limit)
|
|
100
|
+
score = scorer.get_trust_score(agent_id)
|
|
101
|
+
return {
|
|
102
|
+
"agent_id": agent_id, "trust_score": score,
|
|
103
|
+
"signals": signals, "count": len(signals),
|
|
104
|
+
}
|
|
105
|
+
return {"agent_id": agent_id, "signals": [], "count": 0}
|
|
106
|
+
except Exception as e:
|
|
107
|
+
raise HTTPException(status_code=500, detail=f"Trust signals error: {str(e)}")
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under the MIT License - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
|
|
4
|
+
"""SuperLocalMemory V3 - Backup Routes
|
|
5
|
+
- MIT License
|
|
6
|
+
|
|
7
|
+
Routes: /api/backup/status, /api/backup/create, /api/backup/configure, /api/backup/list
|
|
8
|
+
Uses V3 infra.backup.BackupManager.
|
|
9
|
+
"""
|
|
10
|
+
import logging
|
|
11
|
+
|
|
12
|
+
from fastapi import APIRouter, HTTPException
|
|
13
|
+
|
|
14
|
+
from .helpers import BackupConfigRequest, DB_PATH, MEMORY_DIR
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger("superlocalmemory.routes.backup")
|
|
17
|
+
router = APIRouter()
|
|
18
|
+
|
|
19
|
+
# Feature flag
|
|
20
|
+
BACKUP_AVAILABLE = False
|
|
21
|
+
try:
|
|
22
|
+
from superlocalmemory.infra.backup import BackupManager
|
|
23
|
+
BACKUP_AVAILABLE = True
|
|
24
|
+
except ImportError:
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _get_backup_manager() -> "BackupManager":
|
|
29
|
+
"""Get V3 backup manager instance."""
|
|
30
|
+
return BackupManager(db_path=DB_PATH, base_dir=MEMORY_DIR)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@router.get("/api/backup/status")
|
|
34
|
+
async def backup_status():
|
|
35
|
+
"""Get auto-backup system status."""
|
|
36
|
+
if not BACKUP_AVAILABLE:
|
|
37
|
+
return {"status": "not_implemented", "message": "Backup module not available"}
|
|
38
|
+
try:
|
|
39
|
+
manager = _get_backup_manager()
|
|
40
|
+
return manager.get_status()
|
|
41
|
+
except Exception as e:
|
|
42
|
+
raise HTTPException(status_code=500, detail=f"Backup status error: {str(e)}")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@router.post("/api/backup/create")
|
|
46
|
+
async def backup_create():
|
|
47
|
+
"""Create a manual backup immediately."""
|
|
48
|
+
if not BACKUP_AVAILABLE:
|
|
49
|
+
return {"success": False, "message": "Backup module not available"}
|
|
50
|
+
try:
|
|
51
|
+
manager = _get_backup_manager()
|
|
52
|
+
filename = manager.create_backup(label='manual')
|
|
53
|
+
if filename:
|
|
54
|
+
return {
|
|
55
|
+
"success": True, "filename": str(filename),
|
|
56
|
+
"message": f"Backup created: {filename}",
|
|
57
|
+
"status": manager.get_status(),
|
|
58
|
+
}
|
|
59
|
+
return {"success": False, "message": "Backup failed"}
|
|
60
|
+
except Exception as e:
|
|
61
|
+
raise HTTPException(status_code=500, detail=f"Backup create error: {str(e)}")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@router.post("/api/backup/configure")
|
|
65
|
+
async def backup_configure(request: BackupConfigRequest):
|
|
66
|
+
"""Update auto-backup configuration."""
|
|
67
|
+
if not BACKUP_AVAILABLE:
|
|
68
|
+
return {"success": False, "message": "Backup module not available"}
|
|
69
|
+
try:
|
|
70
|
+
manager = _get_backup_manager()
|
|
71
|
+
result = manager.configure(
|
|
72
|
+
interval_hours=request.interval_hours,
|
|
73
|
+
max_backups=request.max_backups,
|
|
74
|
+
enabled=request.enabled,
|
|
75
|
+
)
|
|
76
|
+
return {"success": True, "message": "Backup configuration updated", "status": result}
|
|
77
|
+
except Exception as e:
|
|
78
|
+
raise HTTPException(status_code=500, detail=f"Backup configure error: {str(e)}")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@router.get("/api/backup/list")
|
|
82
|
+
async def backup_list():
|
|
83
|
+
"""List all available backups."""
|
|
84
|
+
if not BACKUP_AVAILABLE:
|
|
85
|
+
return {"backups": [], "count": 0, "message": "Backup module not available"}
|
|
86
|
+
try:
|
|
87
|
+
manager = _get_backup_manager()
|
|
88
|
+
backups = manager.list_backups()
|
|
89
|
+
return {"backups": backups, "count": len(backups)}
|
|
90
|
+
except Exception as e:
|
|
91
|
+
raise HTTPException(status_code=500, detail=f"Backup list error: {str(e)}")
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under the MIT License - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
|
|
4
|
+
"""SuperLocalMemory V3 - Behavioral Routes
|
|
5
|
+
- MIT License
|
|
6
|
+
|
|
7
|
+
Routes: /api/behavioral/status, /api/behavioral/report-outcome
|
|
8
|
+
Uses V3 learning.behavioral.BehavioralPatternStore and learning.outcomes.OutcomeTracker.
|
|
9
|
+
"""
|
|
10
|
+
import json
|
|
11
|
+
import logging
|
|
12
|
+
|
|
13
|
+
from fastapi import APIRouter
|
|
14
|
+
|
|
15
|
+
from .helpers import get_active_profile, MEMORY_DIR
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger("superlocalmemory.routes.behavioral")
|
|
18
|
+
router = APIRouter()
|
|
19
|
+
|
|
20
|
+
LEARNING_DB = MEMORY_DIR / "learning.db"
|
|
21
|
+
|
|
22
|
+
# Feature detection
|
|
23
|
+
BEHAVIORAL_AVAILABLE = False
|
|
24
|
+
try:
|
|
25
|
+
from superlocalmemory.learning.behavioral import BehavioralPatternStore
|
|
26
|
+
from superlocalmemory.learning.outcomes import OutcomeTracker
|
|
27
|
+
BEHAVIORAL_AVAILABLE = True
|
|
28
|
+
except ImportError:
|
|
29
|
+
logger.info("V3 behavioral engine not available")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@router.get("/api/behavioral/status")
|
|
33
|
+
async def behavioral_status():
|
|
34
|
+
"""Get behavioral learning status for active profile."""
|
|
35
|
+
if not BEHAVIORAL_AVAILABLE:
|
|
36
|
+
return {"available": False, "message": "Behavioral engine not available"}
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
profile = get_active_profile()
|
|
40
|
+
db_path = str(LEARNING_DB)
|
|
41
|
+
|
|
42
|
+
# Outcomes
|
|
43
|
+
total_outcomes = 0
|
|
44
|
+
outcome_breakdown = {"success": 0, "failure": 0, "partial": 0}
|
|
45
|
+
recent_outcomes = []
|
|
46
|
+
try:
|
|
47
|
+
tracker = OutcomeTracker(db_path)
|
|
48
|
+
total_outcomes = tracker.get_outcome_count(profile=profile)
|
|
49
|
+
outcome_breakdown = tracker.get_outcome_breakdown(profile=profile)
|
|
50
|
+
recent_outcomes = tracker.get_recent_outcomes(profile=profile, limit=20)
|
|
51
|
+
except Exception as exc:
|
|
52
|
+
logger.debug("outcome tracker: %s", exc)
|
|
53
|
+
|
|
54
|
+
# Patterns
|
|
55
|
+
patterns = []
|
|
56
|
+
cross_project_transfers = 0
|
|
57
|
+
try:
|
|
58
|
+
store = BehavioralPatternStore(db_path)
|
|
59
|
+
patterns = store.get_patterns(profile=profile)
|
|
60
|
+
cross_project_transfers = store.get_cross_project_count(profile=profile)
|
|
61
|
+
except Exception as exc:
|
|
62
|
+
logger.debug("pattern store: %s", exc)
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
"available": True,
|
|
66
|
+
"active_profile": profile,
|
|
67
|
+
"total_outcomes": total_outcomes,
|
|
68
|
+
"outcome_breakdown": outcome_breakdown,
|
|
69
|
+
"patterns": patterns,
|
|
70
|
+
"cross_project_transfers": cross_project_transfers,
|
|
71
|
+
"recent_outcomes": recent_outcomes,
|
|
72
|
+
}
|
|
73
|
+
except Exception as e:
|
|
74
|
+
logger.error("behavioral_status error: %s", e)
|
|
75
|
+
return {"available": False, "error": str(e)}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@router.post("/api/behavioral/report-outcome")
|
|
79
|
+
async def report_outcome(data: dict):
|
|
80
|
+
"""Record an action outcome for behavioral learning.
|
|
81
|
+
|
|
82
|
+
Body: {
|
|
83
|
+
memory_ids: [str, ...],
|
|
84
|
+
outcome: "success" | "failure" | "partial",
|
|
85
|
+
action_type: str (optional),
|
|
86
|
+
context: str (optional)
|
|
87
|
+
}
|
|
88
|
+
"""
|
|
89
|
+
if not BEHAVIORAL_AVAILABLE:
|
|
90
|
+
return {"success": False, "error": "Behavioral engine not available"}
|
|
91
|
+
|
|
92
|
+
memory_ids = data.get('memory_ids')
|
|
93
|
+
outcome = data.get('outcome')
|
|
94
|
+
action_type = data.get('action_type', 'other')
|
|
95
|
+
context_note = data.get('context', '')
|
|
96
|
+
|
|
97
|
+
if not memory_ids or not isinstance(memory_ids, list):
|
|
98
|
+
return {"success": False, "error": "memory_ids must be a non-empty list"}
|
|
99
|
+
|
|
100
|
+
valid_outcomes = ("success", "failure", "partial")
|
|
101
|
+
if outcome not in valid_outcomes:
|
|
102
|
+
return {"success": False, "error": f"outcome must be one of: {valid_outcomes}"}
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
profile = get_active_profile()
|
|
106
|
+
tracker = OutcomeTracker(str(LEARNING_DB))
|
|
107
|
+
|
|
108
|
+
context_dict = {"note": context_note} if context_note else {}
|
|
109
|
+
row_id = tracker.record_outcome(
|
|
110
|
+
memory_ids=memory_ids,
|
|
111
|
+
outcome=outcome,
|
|
112
|
+
action_type=action_type,
|
|
113
|
+
context=context_dict,
|
|
114
|
+
project=profile,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
if row_id is None:
|
|
118
|
+
return {"success": False, "error": "Failed to record outcome"}
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
"success": True, "outcome_id": row_id,
|
|
122
|
+
"active_profile": profile,
|
|
123
|
+
"message": f"Recorded {outcome} outcome for {len(memory_ids)} memories",
|
|
124
|
+
}
|
|
125
|
+
except Exception as e:
|
|
126
|
+
logger.error("report_outcome error: %s", e)
|
|
127
|
+
return {"success": False, "error": str(e)}
|