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
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
# Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
|
|
4
|
-
"""Edge building for the graph engine.
|
|
5
|
-
|
|
6
|
-
Builds similarity edges between memories based on entity overlap
|
|
7
|
-
and TF-IDF vector cosine similarity. Supports HNSW-accelerated
|
|
8
|
-
edge building for large datasets.
|
|
9
|
-
"""
|
|
10
|
-
import sqlite3
|
|
11
|
-
import json
|
|
12
|
-
from pathlib import Path
|
|
13
|
-
from typing import List
|
|
14
|
-
|
|
15
|
-
import numpy as np
|
|
16
|
-
|
|
17
|
-
from graph.constants import logger, cosine_similarity
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class EdgeBuilder:
|
|
21
|
-
"""Build similarity edges between memories based on entity overlap."""
|
|
22
|
-
|
|
23
|
-
def __init__(self, db_path: Path, min_similarity: float = 0.3):
|
|
24
|
-
"""
|
|
25
|
-
Initialize edge builder.
|
|
26
|
-
|
|
27
|
-
Args:
|
|
28
|
-
db_path: Path to SQLite database
|
|
29
|
-
min_similarity: Minimum cosine similarity to create edge
|
|
30
|
-
"""
|
|
31
|
-
self.db_path = db_path
|
|
32
|
-
self.min_similarity = min_similarity
|
|
33
|
-
|
|
34
|
-
def build_edges(self, memory_ids: List[int], vectors: np.ndarray,
|
|
35
|
-
entities_list: List[List[str]]) -> int:
|
|
36
|
-
"""
|
|
37
|
-
Build edges between similar memories.
|
|
38
|
-
|
|
39
|
-
Args:
|
|
40
|
-
memory_ids: List of memory IDs
|
|
41
|
-
vectors: TF-IDF vectors (n x features)
|
|
42
|
-
entities_list: List of entity lists per memory
|
|
43
|
-
|
|
44
|
-
Returns:
|
|
45
|
-
Number of edges created
|
|
46
|
-
"""
|
|
47
|
-
if len(memory_ids) < 2:
|
|
48
|
-
logger.warning("Need at least 2 memories to build edges")
|
|
49
|
-
return 0
|
|
50
|
-
|
|
51
|
-
# Try HNSW-accelerated edge building first (O(n log n))
|
|
52
|
-
use_hnsw = False
|
|
53
|
-
try:
|
|
54
|
-
from hnsw_index import HNSWIndex
|
|
55
|
-
if len(memory_ids) >= 50: # HNSW overhead not worth it for small sets
|
|
56
|
-
use_hnsw = True
|
|
57
|
-
except ImportError:
|
|
58
|
-
pass
|
|
59
|
-
|
|
60
|
-
edges_added = 0
|
|
61
|
-
conn = sqlite3.connect(self.db_path)
|
|
62
|
-
cursor = conn.cursor()
|
|
63
|
-
|
|
64
|
-
try:
|
|
65
|
-
if use_hnsw:
|
|
66
|
-
logger.info("Using HNSW-accelerated edge building for %d memories", len(memory_ids))
|
|
67
|
-
try:
|
|
68
|
-
dim = vectors.shape[1]
|
|
69
|
-
hnsw = HNSWIndex(dimension=dim, max_elements=len(memory_ids))
|
|
70
|
-
hnsw.build(vectors, memory_ids)
|
|
71
|
-
|
|
72
|
-
for i in range(len(memory_ids)):
|
|
73
|
-
neighbors = hnsw.search(vectors[i], k=min(20, len(memory_ids) - 1))
|
|
74
|
-
for neighbor_id, similarity in neighbors:
|
|
75
|
-
if neighbor_id == memory_ids[i]:
|
|
76
|
-
continue # Skip self
|
|
77
|
-
# Only process each pair once (lower ID first)
|
|
78
|
-
if memory_ids[i] > neighbor_id:
|
|
79
|
-
continue
|
|
80
|
-
if similarity >= self.min_similarity:
|
|
81
|
-
# Find indices for entity lookup
|
|
82
|
-
j = memory_ids.index(neighbor_id)
|
|
83
|
-
entities_i = set(entities_list[i])
|
|
84
|
-
entities_j = set(entities_list[j])
|
|
85
|
-
shared = list(entities_i & entities_j)
|
|
86
|
-
rel_type = self._classify_relationship(similarity, shared)
|
|
87
|
-
|
|
88
|
-
cursor.execute('''
|
|
89
|
-
INSERT OR REPLACE INTO graph_edges
|
|
90
|
-
(source_memory_id, target_memory_id, relationship_type,
|
|
91
|
-
weight, shared_entities, similarity_score)
|
|
92
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
93
|
-
''', (
|
|
94
|
-
memory_ids[i], neighbor_id, rel_type,
|
|
95
|
-
float(similarity), json.dumps(shared), float(similarity)
|
|
96
|
-
))
|
|
97
|
-
edges_added += 1
|
|
98
|
-
|
|
99
|
-
except Exception as e:
|
|
100
|
-
logger.warning("HNSW edge building failed, falling back to O(n²): %s", e)
|
|
101
|
-
use_hnsw = False # Fall through to O(n²) below
|
|
102
|
-
|
|
103
|
-
if not use_hnsw:
|
|
104
|
-
# Fallback: O(n²) pairwise cosine similarity
|
|
105
|
-
similarity_matrix = cosine_similarity(vectors)
|
|
106
|
-
|
|
107
|
-
for i in range(len(memory_ids)):
|
|
108
|
-
for j in range(i + 1, len(memory_ids)):
|
|
109
|
-
sim = similarity_matrix[i, j]
|
|
110
|
-
|
|
111
|
-
if sim >= self.min_similarity:
|
|
112
|
-
entities_i = set(entities_list[i])
|
|
113
|
-
entities_j = set(entities_list[j])
|
|
114
|
-
shared = list(entities_i & entities_j)
|
|
115
|
-
rel_type = self._classify_relationship(sim, shared)
|
|
116
|
-
|
|
117
|
-
cursor.execute('''
|
|
118
|
-
INSERT OR REPLACE INTO graph_edges
|
|
119
|
-
(source_memory_id, target_memory_id, relationship_type,
|
|
120
|
-
weight, shared_entities, similarity_score)
|
|
121
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
122
|
-
''', (
|
|
123
|
-
memory_ids[i], memory_ids[j], rel_type,
|
|
124
|
-
float(sim), json.dumps(shared), float(sim)
|
|
125
|
-
))
|
|
126
|
-
edges_added += 1
|
|
127
|
-
|
|
128
|
-
conn.commit()
|
|
129
|
-
logger.info(f"Created {edges_added} edges")
|
|
130
|
-
return edges_added
|
|
131
|
-
|
|
132
|
-
except Exception as e:
|
|
133
|
-
logger.error(f"Edge building failed: {e}")
|
|
134
|
-
conn.rollback()
|
|
135
|
-
return 0
|
|
136
|
-
finally:
|
|
137
|
-
conn.close()
|
|
138
|
-
|
|
139
|
-
def _classify_relationship(self, similarity: float, shared_entities: List[str]) -> str:
|
|
140
|
-
"""
|
|
141
|
-
Classify edge type based on similarity and shared entities.
|
|
142
|
-
|
|
143
|
-
Args:
|
|
144
|
-
similarity: Cosine similarity score
|
|
145
|
-
shared_entities: List of shared entity strings
|
|
146
|
-
|
|
147
|
-
Returns:
|
|
148
|
-
Relationship type: 'similar', 'depends_on', or 'related_to'
|
|
149
|
-
"""
|
|
150
|
-
# Check for dependency keywords
|
|
151
|
-
dependency_keywords = {'dependency', 'require', 'import', 'use', 'need'}
|
|
152
|
-
has_dependency = any(
|
|
153
|
-
any(kw in entity.lower() for kw in dependency_keywords)
|
|
154
|
-
for entity in shared_entities
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
if similarity > 0.7:
|
|
158
|
-
return 'similar'
|
|
159
|
-
elif has_dependency:
|
|
160
|
-
return 'depends_on'
|
|
161
|
-
else:
|
|
162
|
-
return 'related_to'
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
# Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
|
|
4
|
-
"""Entity extraction and cluster naming for the graph engine.
|
|
5
|
-
|
|
6
|
-
Provides TF-IDF based entity extraction from memory content
|
|
7
|
-
and cluster naming utilities.
|
|
8
|
-
"""
|
|
9
|
-
from typing import List, Tuple
|
|
10
|
-
from collections import Counter
|
|
11
|
-
|
|
12
|
-
import numpy as np
|
|
13
|
-
|
|
14
|
-
from graph.constants import logger, TfidfVectorizer
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class EntityExtractor:
|
|
18
|
-
"""Extract key entities/concepts from memory content using TF-IDF."""
|
|
19
|
-
|
|
20
|
-
def __init__(self, max_features: int = 20, min_df: int = 1):
|
|
21
|
-
"""
|
|
22
|
-
Initialize entity extractor.
|
|
23
|
-
|
|
24
|
-
Args:
|
|
25
|
-
max_features: Top N keywords to extract per memory
|
|
26
|
-
min_df: Minimum document frequency (ignore very rare terms)
|
|
27
|
-
"""
|
|
28
|
-
self.max_features = max_features
|
|
29
|
-
self.vectorizer = TfidfVectorizer(
|
|
30
|
-
max_features=max_features,
|
|
31
|
-
stop_words='english',
|
|
32
|
-
ngram_range=(1, 2), # Unigrams + bigrams
|
|
33
|
-
min_df=min_df,
|
|
34
|
-
lowercase=True,
|
|
35
|
-
token_pattern=r'(?u)\b[a-zA-Z][a-zA-Z0-9_-]*\b' # Alphanumeric tokens
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
def extract_entities(self, contents: List[str]) -> Tuple[List[List[str]], np.ndarray]:
|
|
39
|
-
"""
|
|
40
|
-
Extract entities from multiple contents.
|
|
41
|
-
|
|
42
|
-
Args:
|
|
43
|
-
contents: List of memory content strings
|
|
44
|
-
|
|
45
|
-
Returns:
|
|
46
|
-
Tuple of (entities_per_content, tfidf_vectors)
|
|
47
|
-
"""
|
|
48
|
-
if not contents:
|
|
49
|
-
return [], np.array([])
|
|
50
|
-
|
|
51
|
-
try:
|
|
52
|
-
# Fit and transform all contents
|
|
53
|
-
vectors = self.vectorizer.fit_transform(contents)
|
|
54
|
-
feature_names = self.vectorizer.get_feature_names_out()
|
|
55
|
-
|
|
56
|
-
# Extract top entities for each content
|
|
57
|
-
all_entities = []
|
|
58
|
-
for idx in range(len(contents)):
|
|
59
|
-
scores = vectors[idx].toarray()[0]
|
|
60
|
-
|
|
61
|
-
# Get indices of top features
|
|
62
|
-
top_indices = np.argsort(scores)[::-1]
|
|
63
|
-
|
|
64
|
-
# Extract entities with score > 0
|
|
65
|
-
entities = [
|
|
66
|
-
feature_names[i]
|
|
67
|
-
for i in top_indices
|
|
68
|
-
if scores[i] > 0.05 # Minimum threshold
|
|
69
|
-
][:self.max_features]
|
|
70
|
-
|
|
71
|
-
all_entities.append(entities)
|
|
72
|
-
|
|
73
|
-
return all_entities, vectors.toarray()
|
|
74
|
-
|
|
75
|
-
except Exception as e:
|
|
76
|
-
logger.error(f"Entity extraction failed: {e}")
|
|
77
|
-
return [[] for _ in contents], np.zeros((len(contents), 1))
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
class ClusterNamer:
|
|
81
|
-
"""Enhanced cluster naming with optional LLM support (future)."""
|
|
82
|
-
|
|
83
|
-
@staticmethod
|
|
84
|
-
def generate_name_tfidf(entities: List[str]) -> str:
|
|
85
|
-
"""Generate name from entity list (TF-IDF fallback)."""
|
|
86
|
-
if not entities:
|
|
87
|
-
return "Unnamed Cluster"
|
|
88
|
-
|
|
89
|
-
entity_counts = Counter(entities)
|
|
90
|
-
top_entities = [e for e, _ in entity_counts.most_common(2)]
|
|
91
|
-
|
|
92
|
-
if len(top_entities) >= 2:
|
|
93
|
-
return f"{top_entities[0].title()} & {top_entities[1].title()}"
|
|
94
|
-
else:
|
|
95
|
-
return f"{top_entities[0].title()} Contexts"
|
package/src/graph/graph_core.py
DELETED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
# Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
|
|
4
|
-
"""GraphEngine - Main orchestrator for the knowledge graph.
|
|
5
|
-
|
|
6
|
-
Coordinates entity extraction, edge building, community detection,
|
|
7
|
-
and graph traversal operations. All processing is local.
|
|
8
|
-
"""
|
|
9
|
-
import sqlite3
|
|
10
|
-
import json
|
|
11
|
-
import time
|
|
12
|
-
from pathlib import Path
|
|
13
|
-
from typing import List, Dict
|
|
14
|
-
|
|
15
|
-
import numpy as np
|
|
16
|
-
|
|
17
|
-
from graph.constants import (
|
|
18
|
-
logger, MEMORY_DIR, DB_PATH, IGRAPH_AVAILABLE, cosine_similarity
|
|
19
|
-
)
|
|
20
|
-
from graph.entity_extractor import EntityExtractor
|
|
21
|
-
from graph.edge_builder import EdgeBuilder
|
|
22
|
-
from graph.cluster_builder import ClusterBuilder
|
|
23
|
-
from graph.schema import ensure_graph_tables
|
|
24
|
-
from graph.build_helpers import apply_sampling, clear_profile_graph_data
|
|
25
|
-
from graph.graph_search import (
|
|
26
|
-
get_related as _get_related,
|
|
27
|
-
get_cluster_members as _get_cluster_members,
|
|
28
|
-
get_stats as _get_stats,
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class GraphEngine:
|
|
33
|
-
"""Main graph engine coordinating all graph operations."""
|
|
34
|
-
|
|
35
|
-
def __init__(self, db_path: Path = DB_PATH):
|
|
36
|
-
"""Initialize graph engine."""
|
|
37
|
-
self.db_path = db_path
|
|
38
|
-
self.entity_extractor = EntityExtractor(max_features=20)
|
|
39
|
-
self.edge_builder = EdgeBuilder(db_path)
|
|
40
|
-
self.cluster_builder = ClusterBuilder(db_path)
|
|
41
|
-
self._ensure_graph_tables()
|
|
42
|
-
|
|
43
|
-
def _get_active_profile(self) -> str:
|
|
44
|
-
"""Get the currently active profile name from config."""
|
|
45
|
-
config_file = MEMORY_DIR / "profiles.json"
|
|
46
|
-
if config_file.exists():
|
|
47
|
-
try:
|
|
48
|
-
with open(config_file, 'r') as f:
|
|
49
|
-
config = json.load(f)
|
|
50
|
-
return config.get('active_profile', 'default')
|
|
51
|
-
except (json.JSONDecodeError, IOError):
|
|
52
|
-
pass
|
|
53
|
-
return 'default'
|
|
54
|
-
|
|
55
|
-
def _ensure_graph_tables(self):
|
|
56
|
-
"""Create graph tables if they don't exist, or recreate if schema is incomplete."""
|
|
57
|
-
ensure_graph_tables(self.db_path)
|
|
58
|
-
|
|
59
|
-
def build_graph(self, min_similarity: float = 0.3) -> Dict[str, any]:
|
|
60
|
-
"""
|
|
61
|
-
Build complete knowledge graph from all memories.
|
|
62
|
-
|
|
63
|
-
Args:
|
|
64
|
-
min_similarity: Minimum cosine similarity for edge creation
|
|
65
|
-
|
|
66
|
-
Returns:
|
|
67
|
-
Dictionary with build statistics
|
|
68
|
-
"""
|
|
69
|
-
start_time = time.time()
|
|
70
|
-
logger.info("Starting full graph build...")
|
|
71
|
-
conn = sqlite3.connect(self.db_path)
|
|
72
|
-
cursor = conn.cursor()
|
|
73
|
-
|
|
74
|
-
try:
|
|
75
|
-
# Check required tables
|
|
76
|
-
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
|
|
77
|
-
existing_tables = {row[0] for row in cursor.fetchall()}
|
|
78
|
-
missing = {'memories', 'graph_edges', 'graph_nodes', 'graph_clusters'} - existing_tables
|
|
79
|
-
if missing:
|
|
80
|
-
logger.error(f"Missing required tables: {missing}")
|
|
81
|
-
return {'success': False, 'error': 'database_not_initialized',
|
|
82
|
-
'message': f"Database not initialized. Missing tables: {', '.join(missing)}",
|
|
83
|
-
'fix': "Run 'superlocalmemoryv2-status' first to initialize the database, or add some memories."}
|
|
84
|
-
|
|
85
|
-
active_profile = self._get_active_profile()
|
|
86
|
-
logger.info(f"Building graph for profile: {active_profile}")
|
|
87
|
-
memories = cursor.execute(
|
|
88
|
-
'SELECT id, content, summary FROM memories WHERE profile = ? ORDER BY id',
|
|
89
|
-
(active_profile,)).fetchall()
|
|
90
|
-
|
|
91
|
-
if len(memories) == 0:
|
|
92
|
-
return {'success': False, 'error': 'no_memories',
|
|
93
|
-
'message': 'No memories found in database.',
|
|
94
|
-
'fix': "Add some memories first: superlocalmemoryv2-remember 'Your content here'"}
|
|
95
|
-
if len(memories) < 2:
|
|
96
|
-
return {'success': False, 'error': 'insufficient_memories',
|
|
97
|
-
'message': 'Need at least 2 memories to build knowledge graph.',
|
|
98
|
-
'memories': len(memories),
|
|
99
|
-
'fix': "Add more memories: superlocalmemoryv2-remember 'Your content here'"}
|
|
100
|
-
|
|
101
|
-
memories = apply_sampling(cursor, memories, active_profile)
|
|
102
|
-
clear_profile_graph_data(cursor, conn, memories, active_profile)
|
|
103
|
-
|
|
104
|
-
logger.info(f"Processing {len(memories)} memories")
|
|
105
|
-
memory_ids = [m[0] for m in memories]
|
|
106
|
-
contents = [f"{m[1]} {m[2] or ''}" for m in memories]
|
|
107
|
-
entities_list, vectors = self.entity_extractor.extract_entities(contents)
|
|
108
|
-
|
|
109
|
-
for memory_id, entities, vector in zip(memory_ids, entities_list, vectors):
|
|
110
|
-
cursor.execute('''
|
|
111
|
-
INSERT INTO graph_nodes (memory_id, entities, embedding_vector)
|
|
112
|
-
VALUES (?, ?, ?)
|
|
113
|
-
''', (memory_id, json.dumps(entities), json.dumps(vector.tolist())))
|
|
114
|
-
conn.commit()
|
|
115
|
-
logger.info(f"Stored {len(memory_ids)} graph nodes")
|
|
116
|
-
|
|
117
|
-
edges_count = self.edge_builder.build_edges(memory_ids, vectors, entities_list)
|
|
118
|
-
clusters_count = self.cluster_builder.detect_communities()
|
|
119
|
-
hierarchical_stats = self.cluster_builder.hierarchical_cluster()
|
|
120
|
-
subclusters = hierarchical_stats.get('subclusters_created', 0)
|
|
121
|
-
summaries = self.cluster_builder.generate_cluster_summaries()
|
|
122
|
-
elapsed = time.time() - start_time
|
|
123
|
-
|
|
124
|
-
stats = {
|
|
125
|
-
'success': True, 'memories': len(memories), 'nodes': len(memory_ids),
|
|
126
|
-
'edges': edges_count, 'clusters': clusters_count, 'subclusters': subclusters,
|
|
127
|
-
'max_depth': hierarchical_stats.get('depth_reached', 0),
|
|
128
|
-
'summaries_generated': summaries, 'time_seconds': round(elapsed, 2)
|
|
129
|
-
}
|
|
130
|
-
if not IGRAPH_AVAILABLE:
|
|
131
|
-
stats['warning'] = 'igraph/leidenalg not installed — graph built without clustering. Install with: pip3 install python-igraph leidenalg'
|
|
132
|
-
logger.info(f"Graph build complete: {stats}")
|
|
133
|
-
return stats
|
|
134
|
-
|
|
135
|
-
except Exception as e:
|
|
136
|
-
logger.error(f"Graph build failed: {e}")
|
|
137
|
-
conn.rollback()
|
|
138
|
-
return {'success': False, 'error': str(e)}
|
|
139
|
-
finally:
|
|
140
|
-
conn.close()
|
|
141
|
-
|
|
142
|
-
def extract_entities(self, memory_id: int) -> List[str]:
|
|
143
|
-
"""Extract entities for a single memory."""
|
|
144
|
-
conn = sqlite3.connect(self.db_path)
|
|
145
|
-
cursor = conn.cursor()
|
|
146
|
-
try:
|
|
147
|
-
memory = cursor.execute(
|
|
148
|
-
'SELECT content, summary FROM memories WHERE id = ?', (memory_id,)
|
|
149
|
-
).fetchone()
|
|
150
|
-
if not memory:
|
|
151
|
-
return []
|
|
152
|
-
content = f"{memory[0]} {memory[1] or ''}"
|
|
153
|
-
entities_list, _ = self.entity_extractor.extract_entities([content])
|
|
154
|
-
return entities_list[0] if entities_list else []
|
|
155
|
-
finally:
|
|
156
|
-
conn.close()
|
|
157
|
-
|
|
158
|
-
def get_related(self, memory_id: int, max_hops: int = 2) -> List[Dict]:
|
|
159
|
-
"""Get memories connected to this memory via graph edges (active profile only)."""
|
|
160
|
-
return _get_related(self.db_path, memory_id, max_hops)
|
|
161
|
-
|
|
162
|
-
def get_cluster_members(self, cluster_id: int) -> List[Dict]:
|
|
163
|
-
"""Get all memories in a cluster (filtered by active profile)."""
|
|
164
|
-
return _get_cluster_members(self.db_path, cluster_id)
|
|
165
|
-
|
|
166
|
-
def add_memory_incremental(self, memory_id: int) -> bool:
|
|
167
|
-
"""Add single memory to existing graph (incremental update)."""
|
|
168
|
-
conn = sqlite3.connect(self.db_path)
|
|
169
|
-
cursor = conn.cursor()
|
|
170
|
-
try:
|
|
171
|
-
memory = cursor.execute(
|
|
172
|
-
'SELECT content, summary FROM memories WHERE id = ?', (memory_id,)
|
|
173
|
-
).fetchone()
|
|
174
|
-
if not memory:
|
|
175
|
-
return False
|
|
176
|
-
|
|
177
|
-
content = f"{memory[0]} {memory[1] or ''}"
|
|
178
|
-
entities_list, vector = self.entity_extractor.extract_entities([content])
|
|
179
|
-
if not entities_list:
|
|
180
|
-
return False
|
|
181
|
-
|
|
182
|
-
new_entities, new_vector = entities_list[0], vector[0]
|
|
183
|
-
cursor.execute('''
|
|
184
|
-
INSERT OR REPLACE INTO graph_nodes (memory_id, entities, embedding_vector)
|
|
185
|
-
VALUES (?, ?, ?)
|
|
186
|
-
''', (memory_id, json.dumps(new_entities), json.dumps(new_vector.tolist())))
|
|
187
|
-
|
|
188
|
-
active_profile = self._get_active_profile()
|
|
189
|
-
existing = cursor.execute('''
|
|
190
|
-
SELECT gn.memory_id, gn.embedding_vector, gn.entities
|
|
191
|
-
FROM graph_nodes gn JOIN memories m ON gn.memory_id = m.id
|
|
192
|
-
WHERE gn.memory_id != ? AND m.profile = ?
|
|
193
|
-
''', (memory_id, active_profile)).fetchall()
|
|
194
|
-
|
|
195
|
-
edges_added = 0
|
|
196
|
-
for existing_id, ev_json, ee_json in existing:
|
|
197
|
-
ev = np.array(json.loads(ev_json))
|
|
198
|
-
sim = cosine_similarity([new_vector], [ev])[0][0]
|
|
199
|
-
if sim >= self.edge_builder.min_similarity:
|
|
200
|
-
ee = json.loads(ee_json)
|
|
201
|
-
shared = list(set(new_entities) & set(ee))
|
|
202
|
-
rel_type = self.edge_builder._classify_relationship(sim, shared)
|
|
203
|
-
cursor.execute('''
|
|
204
|
-
INSERT OR REPLACE INTO graph_edges
|
|
205
|
-
(source_memory_id, target_memory_id, relationship_type,
|
|
206
|
-
weight, shared_entities, similarity_score)
|
|
207
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
208
|
-
''', (memory_id, existing_id, rel_type,
|
|
209
|
-
float(sim), json.dumps(shared), float(sim)))
|
|
210
|
-
edges_added += 1
|
|
211
|
-
|
|
212
|
-
conn.commit()
|
|
213
|
-
logger.info(f"Added memory {memory_id} to graph with {edges_added} edges")
|
|
214
|
-
if edges_added > 5:
|
|
215
|
-
logger.info("Significant graph change - consider re-clustering")
|
|
216
|
-
return True
|
|
217
|
-
except Exception as e:
|
|
218
|
-
logger.error(f"Incremental add failed: {e}")
|
|
219
|
-
conn.rollback()
|
|
220
|
-
return False
|
|
221
|
-
finally:
|
|
222
|
-
conn.close()
|
|
223
|
-
|
|
224
|
-
def get_stats(self) -> Dict[str, any]:
|
|
225
|
-
"""Get graph statistics for the active profile."""
|
|
226
|
-
return _get_stats(self.db_path)
|