superlocalmemory 3.4.0__tar.gz → 3.4.1__tar.gz
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.
- {superlocalmemory-3.4.0/src/superlocalmemory.egg-info → superlocalmemory-3.4.1}/PKG-INFO +8 -9
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/README.md +7 -8
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/pyproject.toml +1 -1
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/engine_wiring.py +5 -1
- superlocalmemory-3.4.1/src/superlocalmemory/core/graph_analyzer.py +441 -0
- superlocalmemory-3.4.1/src/superlocalmemory/learning/consolidation_worker.py +477 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/entity_channel.py +135 -4
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/spreading_activation.py +45 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/api.py +9 -1
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/behavioral.py +8 -4
- superlocalmemory-3.4.1/src/superlocalmemory/server/routes/chat.py +320 -0
- superlocalmemory-3.4.1/src/superlocalmemory/server/routes/insights.py +368 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/learning.py +106 -6
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/memories.py +20 -9
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/stats.py +25 -3
- superlocalmemory-3.4.1/src/superlocalmemory/server/routes/timeline.py +252 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/v3_api.py +161 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/ui.py +8 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/index.html +168 -58
- superlocalmemory-3.4.1/src/superlocalmemory/ui/js/graph-event-bus.js +83 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/graph-filters.js +1 -1
- superlocalmemory-3.4.1/src/superlocalmemory/ui/js/knowledge-graph.js +942 -0
- superlocalmemory-3.4.1/src/superlocalmemory/ui/js/memory-chat.js +344 -0
- superlocalmemory-3.4.1/src/superlocalmemory/ui/js/memory-timeline.js +265 -0
- superlocalmemory-3.4.1/src/superlocalmemory/ui/js/quick-actions.js +334 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1/src/superlocalmemory.egg-info}/PKG-INFO +8 -9
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory.egg-info/SOURCES.txt +8 -0
- superlocalmemory-3.4.0/src/superlocalmemory/core/graph_analyzer.py +0 -199
- superlocalmemory-3.4.0/src/superlocalmemory/learning/consolidation_worker.py +0 -289
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/AUTHORS.md +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/LICENSE +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/NOTICE +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/setup.cfg +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/attribution/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/attribution/mathematical_dna.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/attribution/signer.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/attribution/watermark.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/cli/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/cli/commands.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/cli/daemon.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/cli/json_output.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/cli/main.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/cli/migrate_cmd.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/cli/pending_store.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/cli/post_install.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/cli/setup_wizard.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/blast_radius.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/bridge/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/bridge/entity_resolver.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/bridge/event_listeners.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/bridge/fact_enricher.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/bridge/hebbian_linker.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/bridge/temporal_checker.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/changes.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/communities.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/config.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/database.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/extractors/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/extractors/python.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/extractors/typescript.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/flows.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/git_hooks.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/graph_engine.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/graph_store.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/incremental.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/models.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/parser.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/resolver.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/search.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/service.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/code_graph/watcher.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/compliance/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/compliance/abac.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/compliance/audit.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/compliance/eu_ai_act.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/compliance/gdpr.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/compliance/lifecycle.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/compliance/retention.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/compliance/scheduler.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/config.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/consolidation_engine.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/embedding_worker.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/embeddings.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/engine.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/hooks.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/maintenance.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/maintenance_scheduler.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/modes.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/ollama_embedder.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/profiles.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/recall_pipeline.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/recall_worker.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/registry.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/reranker_worker.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/store_pipeline.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/summarizer.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/worker_pool.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/dynamics/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/dynamics/activation_guided_quantization.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/dynamics/eap_scheduler.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/auto_linker.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/cognitive_consolidator.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/consolidator.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/context_generator.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/emotional.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/entity_resolver.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/entropy_gate.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/fact_extractor.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/foresight.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/graph_builder.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/observation_builder.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/scene_builder.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/signal_inference.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/temporal_parser.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/temporal_validator.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/encoding/type_router.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/hooks/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/hooks/auto_capture.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/hooks/auto_invoker.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/hooks/auto_parameterize.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/hooks/auto_recall.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/hooks/claude_code_hooks.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/hooks/hook_handlers.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/hooks/ide_connector.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/hooks/rules_engine.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/infra/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/infra/auth_middleware.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/infra/backup.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/infra/cache_manager.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/infra/event_bus.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/infra/heartbeat_monitor.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/infra/pid_manager.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/infra/process_reaper.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/infra/rate_limiter.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/infra/webhook_dispatcher.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/adaptive.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/behavioral.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/behavioral_listener.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/bootstrap.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/consolidation_quantization_worker.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/cross_project.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/database.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/engagement.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/features.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/feedback.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/forgetting_scheduler.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/outcomes.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/project_context.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/quantization_scheduler.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/ranker.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/signals.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/source_quality.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/learning/workflows.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/llm/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/llm/backbone.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/math/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/math/ebbinghaus.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/math/fisher.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/math/fisher_quantized.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/math/hopfield.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/math/langevin.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/math/polar_quant.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/math/qjl.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/math/sheaf.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/math/turbo_quant.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/mcp/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/mcp/resources.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/mcp/server.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/mcp/shared.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/mcp/tools.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/mcp/tools_active.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/mcp/tools_code_graph.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/mcp/tools_core.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/mcp/tools_v28.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/mcp/tools_v3.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/mcp/tools_v33.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/parameterization/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/parameterization/pattern_extractor.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/parameterization/pii_filter.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/parameterization/prompt_injector.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/parameterization/prompt_lifecycle.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/parameterization/soft_prompt_generator.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/agentic.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/ann_index.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/bm25_channel.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/bridge_discovery.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/channel_registry.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/engine.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/forgetting_filter.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/fusion.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/hopfield_channel.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/profile_channel.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/quantization_aware_search.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/reranker.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/semantic_channel.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/strategy.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/temporal_channel.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/retrieval/vector_store.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/agents.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/backup.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/compliance.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/data_io.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/events.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/helpers.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/lifecycle.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/profiles.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/routes/ws.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/server/security_middleware.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/storage/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/storage/access_control.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/storage/access_log.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/storage/database.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/storage/embedding_migrator.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/storage/migration_v33.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/storage/migrations.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/storage/models.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/storage/quantized_store.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/storage/schema.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/storage/schema_code_graph.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/storage/schema_v32.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/storage/v2_migrator.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/trust/__init__.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/trust/gate.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/trust/provenance.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/trust/scorer.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/trust/signals.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/agents.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/auto-settings.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/behavioral.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/clusters.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/compliance.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/core.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/dashboard.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/events.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/fact-detail.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/feedback.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/graph-core.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/graph-interactions.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/graph-ui.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/ide-status.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/init.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/learning.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/lifecycle.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/math-health.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/memories.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/modal.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/patterns.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/profiles.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/recall-lab.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/search.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/settings.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/timeline.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/ui/js/trust-dashboard.js +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory.egg-info/dependency_links.txt +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory.egg-info/entry_points.txt +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory.egg-info/requires.txt +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory.egg-info/top_level.txt +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_auto_hooks.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_behavioral_full.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_claude_hooks.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_cli.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_cli_json.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_cli_v33.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_compliance_full.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_config_system.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_engine_hooks.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_event_bus.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_features.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_final_locomo_mini.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_hook_handlers.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_ide_connector.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_infra.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_learning_advanced.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_learning_collectors.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_llm_provider.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_mcp_server.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_migration.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_post_install.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_ranker.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_trust_full.py +0 -0
- {superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/tests/test_v3_api.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: superlocalmemory
|
|
3
|
-
Version: 3.4.
|
|
3
|
+
Version: 3.4.1
|
|
4
4
|
Summary: Information-geometric agent memory with mathematical guarantees
|
|
5
5
|
Author-email: Varun Pratap Bhardwaj <admin@superlocalmemory.com>
|
|
6
6
|
License: AGPL-3.0-or-later
|
|
@@ -413,20 +413,19 @@ slm dashboard # Opens at http://localhost:8765
|
|
|
413
413
|
|
|
414
414
|
<details open>
|
|
415
415
|
<summary><strong>Dashboard Screenshots</strong> (click to collapse)</summary>
|
|
416
|
-
<p align="center"><img src="docs/screenshots/01-dashboard-main.png" alt="Dashboard" width="600"/></p>
|
|
416
|
+
<p align="center"><img src="docs/screenshots/01-dashboard-main.png" alt="Dashboard Overview — 3,100+ memories, 430K connections" width="600"/></p>
|
|
417
417
|
<p align="center">
|
|
418
|
-
<img src="docs/screenshots/02-knowledge-graph.png" alt="Graph" width="
|
|
419
|
-
<img src="docs/screenshots/
|
|
420
|
-
<img src="docs/screenshots/05-trust-dashboard.png" alt="Trust" width="190"/>
|
|
418
|
+
<img src="docs/screenshots/02-knowledge-graph.png" alt="Knowledge Graph — Sigma.js WebGL with community detection, chat, quick actions, timeline" width="290"/>
|
|
419
|
+
<img src="docs/screenshots/06-graph-communities.png" alt="Graph Communities — Louvain clustering with colored nodes" width="290"/>
|
|
421
420
|
</p>
|
|
422
421
|
<p align="center">
|
|
423
|
-
<img src="docs/screenshots/
|
|
424
|
-
<img src="docs/screenshots/
|
|
425
|
-
<img src="docs/screenshots/
|
|
422
|
+
<img src="docs/screenshots/03-patterns-learning.png" alt="Patterns — 50 learned behavioral patterns with confidence bars" width="190"/>
|
|
423
|
+
<img src="docs/screenshots/04-learning-dashboard.png" alt="Learning — 722 signals, ML Model phase, tech preferences" width="190"/>
|
|
424
|
+
<img src="docs/screenshots/05-behavioral-analysis.png" alt="Behavioral — pattern analysis with confidence distribution" width="190"/>
|
|
426
425
|
</p>
|
|
427
426
|
</details>
|
|
428
427
|
|
|
429
|
-
|
|
428
|
+
**v3.4.1 Visual Intelligence:** Sigma.js WebGL knowledge graph with community detection (Louvain/Leiden), 5 quick insight actions, D3 memory timeline, graph-enhanced retrieval (PageRank bias + community boost + contradiction suppression), and 56 auto-mined behavioral patterns. 23+ tabs. Runs locally — no data leaves your machine.
|
|
430
429
|
|
|
431
430
|
---
|
|
432
431
|
|
|
@@ -341,20 +341,19 @@ slm dashboard # Opens at http://localhost:8765
|
|
|
341
341
|
|
|
342
342
|
<details open>
|
|
343
343
|
<summary><strong>Dashboard Screenshots</strong> (click to collapse)</summary>
|
|
344
|
-
<p align="center"><img src="docs/screenshots/01-dashboard-main.png" alt="Dashboard" width="600"/></p>
|
|
344
|
+
<p align="center"><img src="docs/screenshots/01-dashboard-main.png" alt="Dashboard Overview — 3,100+ memories, 430K connections" width="600"/></p>
|
|
345
345
|
<p align="center">
|
|
346
|
-
<img src="docs/screenshots/02-knowledge-graph.png" alt="Graph" width="
|
|
347
|
-
<img src="docs/screenshots/
|
|
348
|
-
<img src="docs/screenshots/05-trust-dashboard.png" alt="Trust" width="190"/>
|
|
346
|
+
<img src="docs/screenshots/02-knowledge-graph.png" alt="Knowledge Graph — Sigma.js WebGL with community detection, chat, quick actions, timeline" width="290"/>
|
|
347
|
+
<img src="docs/screenshots/06-graph-communities.png" alt="Graph Communities — Louvain clustering with colored nodes" width="290"/>
|
|
349
348
|
</p>
|
|
350
349
|
<p align="center">
|
|
351
|
-
<img src="docs/screenshots/
|
|
352
|
-
<img src="docs/screenshots/
|
|
353
|
-
<img src="docs/screenshots/
|
|
350
|
+
<img src="docs/screenshots/03-patterns-learning.png" alt="Patterns — 50 learned behavioral patterns with confidence bars" width="190"/>
|
|
351
|
+
<img src="docs/screenshots/04-learning-dashboard.png" alt="Learning — 722 signals, ML Model phase, tech preferences" width="190"/>
|
|
352
|
+
<img src="docs/screenshots/05-behavioral-analysis.png" alt="Behavioral — pattern analysis with confidence distribution" width="190"/>
|
|
354
353
|
</p>
|
|
355
354
|
</details>
|
|
356
355
|
|
|
357
|
-
|
|
356
|
+
**v3.4.1 Visual Intelligence:** Sigma.js WebGL knowledge graph with community detection (Louvain/Leiden), 5 quick insight actions, D3 memory timeline, graph-enhanced retrieval (PageRank bias + community boost + contradiction suppression), and 56 auto-mined behavioral patterns. 23+ tabs. Runs locally — no data leaves your machine.
|
|
358
357
|
|
|
359
358
|
---
|
|
360
359
|
|
{superlocalmemory-3.4.0 → superlocalmemory-3.4.1}/src/superlocalmemory/core/engine_wiring.py
RENAMED
|
@@ -364,7 +364,11 @@ def _init_spreading_activation(
|
|
|
364
364
|
SpreadingActivation,
|
|
365
365
|
SpreadingActivationConfig,
|
|
366
366
|
)
|
|
367
|
-
sa_config = SpreadingActivationConfig(
|
|
367
|
+
sa_config = SpreadingActivationConfig(
|
|
368
|
+
enabled=True,
|
|
369
|
+
use_pagerank_bias=True, # v3.4.1: PageRank-weighted propagation
|
|
370
|
+
community_boost=0.15, # v3.4.1: 15% boost for same-community nodes
|
|
371
|
+
)
|
|
368
372
|
return SpreadingActivation(
|
|
369
373
|
db=db, vector_store=vector_store, config=sa_config,
|
|
370
374
|
)
|
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under the Elastic License 2.0 - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory V3
|
|
4
|
+
|
|
5
|
+
"""Graph structural analysis -- PageRank, community detection, centrality.
|
|
6
|
+
|
|
7
|
+
Reads BOTH graph_edges and association_edges for the full graph picture.
|
|
8
|
+
Stores results in fact_importance table.
|
|
9
|
+
Called during consolidation (Phase 5), not at query time.
|
|
10
|
+
|
|
11
|
+
v3.4.1: Added Leiden community detection (optional), TF-IDF community labels,
|
|
12
|
+
bridge score detection. Frontend uses Louvain; backend uses Leiden/LP.
|
|
13
|
+
|
|
14
|
+
Part of Qualixar | Author: Varun Pratap Bhardwaj
|
|
15
|
+
License: AGPL-3.0-or-later
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import json
|
|
21
|
+
import logging
|
|
22
|
+
from collections import Counter, defaultdict
|
|
23
|
+
from math import log
|
|
24
|
+
from typing import Any
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class GraphAnalyzer:
|
|
30
|
+
"""Compute structural importance metrics for the memory graph.
|
|
31
|
+
|
|
32
|
+
- PageRank: global structural importance via networkx
|
|
33
|
+
- Community detection: Label Propagation via networkx
|
|
34
|
+
- Degree centrality: connection count normalization
|
|
35
|
+
|
|
36
|
+
Reads BOTH graph_edges and association_edges (Rule 13).
|
|
37
|
+
Stores results in fact_importance table.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self, db: Any) -> None:
|
|
41
|
+
self._db = db
|
|
42
|
+
|
|
43
|
+
def compute_and_store(self, profile_id: str) -> dict[str, Any]:
|
|
44
|
+
"""Run all analyses and persist to fact_importance.
|
|
45
|
+
|
|
46
|
+
v3.4.1: Now uses Leiden (falls back to Label Propagation),
|
|
47
|
+
generates TF-IDF community labels, computes bridge scores.
|
|
48
|
+
|
|
49
|
+
Returns summary dict with node_count, community_count, top_5_nodes,
|
|
50
|
+
bridge_count, top_bridge_nodes, community_labels.
|
|
51
|
+
"""
|
|
52
|
+
try:
|
|
53
|
+
graph = self._build_networkx_graph(profile_id)
|
|
54
|
+
if graph.number_of_nodes() == 0:
|
|
55
|
+
return {
|
|
56
|
+
"node_count": 0,
|
|
57
|
+
"edge_count": 0,
|
|
58
|
+
"community_count": 0,
|
|
59
|
+
"top_5_nodes": [],
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
pagerank = self.compute_pagerank(graph)
|
|
63
|
+
communities = self.detect_communities_leiden(graph, profile_id)
|
|
64
|
+
centrality = self._compute_degree_centrality(graph)
|
|
65
|
+
bridge_scores = self.compute_bridge_scores(graph)
|
|
66
|
+
labels = self.compute_community_labels(profile_id, communities)
|
|
67
|
+
|
|
68
|
+
# v3.4.1: Ensure bridge_score column exists (idempotent migration)
|
|
69
|
+
try:
|
|
70
|
+
columns = self._db.execute(
|
|
71
|
+
"PRAGMA table_info(fact_importance)", (),
|
|
72
|
+
)
|
|
73
|
+
has_bridge = any(
|
|
74
|
+
dict(c).get("name") == "bridge_score" for c in columns
|
|
75
|
+
)
|
|
76
|
+
if not has_bridge:
|
|
77
|
+
self._db.execute(
|
|
78
|
+
"ALTER TABLE fact_importance "
|
|
79
|
+
"ADD COLUMN bridge_score REAL DEFAULT 0.0",
|
|
80
|
+
(),
|
|
81
|
+
)
|
|
82
|
+
except Exception:
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
# Persist to fact_importance (with bridge_score)
|
|
86
|
+
for node_id in graph.nodes():
|
|
87
|
+
pr_score = pagerank.get(node_id, 0.0)
|
|
88
|
+
comm_id = communities.get(node_id)
|
|
89
|
+
deg_cent = centrality.get(node_id, 0.0)
|
|
90
|
+
br_score = bridge_scores.get(node_id, 0.0)
|
|
91
|
+
try:
|
|
92
|
+
self._db.execute(
|
|
93
|
+
"INSERT OR REPLACE INTO fact_importance "
|
|
94
|
+
"(fact_id, profile_id, pagerank_score, community_id, "
|
|
95
|
+
" degree_centrality, bridge_score, computed_at) "
|
|
96
|
+
"VALUES (?, ?, ?, ?, ?, ?, datetime('now'))",
|
|
97
|
+
(node_id, profile_id, round(pr_score, 6),
|
|
98
|
+
comm_id, round(deg_cent, 4),
|
|
99
|
+
round(br_score, 6)),
|
|
100
|
+
)
|
|
101
|
+
except Exception:
|
|
102
|
+
# Fallback without bridge_score if column doesn't exist
|
|
103
|
+
self._db.execute(
|
|
104
|
+
"INSERT OR REPLACE INTO fact_importance "
|
|
105
|
+
"(fact_id, profile_id, pagerank_score, community_id, "
|
|
106
|
+
" degree_centrality, computed_at) "
|
|
107
|
+
"VALUES (?, ?, ?, ?, ?, datetime('now'))",
|
|
108
|
+
(node_id, profile_id, round(pr_score, 6),
|
|
109
|
+
comm_id, round(deg_cent, 4)),
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# v3.4.1: Persist community labels to JSON sidecar
|
|
113
|
+
try:
|
|
114
|
+
from pathlib import Path as _Path
|
|
115
|
+
labels_dir = _Path.home() / ".superlocalmemory"
|
|
116
|
+
labels_dir.mkdir(parents=True, exist_ok=True)
|
|
117
|
+
labels_path = labels_dir / f"{profile_id}_community_labels.json"
|
|
118
|
+
labels_path.write_text(json.dumps(labels, indent=2))
|
|
119
|
+
except Exception:
|
|
120
|
+
pass
|
|
121
|
+
|
|
122
|
+
top_5 = sorted(
|
|
123
|
+
pagerank.items(), key=lambda x: x[1], reverse=True,
|
|
124
|
+
)[:5]
|
|
125
|
+
unique_communities = len(
|
|
126
|
+
set(c for c in communities.values() if c is not None),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
bridge_count = len(
|
|
130
|
+
[s for s in bridge_scores.values() if s > 0.1],
|
|
131
|
+
)
|
|
132
|
+
top_bridges = sorted(
|
|
133
|
+
bridge_scores.items(), key=lambda x: -x[1],
|
|
134
|
+
)[:5]
|
|
135
|
+
|
|
136
|
+
logger.info(
|
|
137
|
+
"GraphAnalyzer: %d nodes, %d communities, %d bridges, "
|
|
138
|
+
"labels=%s",
|
|
139
|
+
graph.number_of_nodes(), unique_communities,
|
|
140
|
+
bridge_count, labels,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
"node_count": graph.number_of_nodes(),
|
|
145
|
+
"edge_count": graph.number_of_edges(),
|
|
146
|
+
"community_count": unique_communities,
|
|
147
|
+
"top_5_nodes": [
|
|
148
|
+
(nid, round(score, 4)) for nid, score in top_5
|
|
149
|
+
],
|
|
150
|
+
"bridge_count": bridge_count,
|
|
151
|
+
"top_bridge_nodes": [
|
|
152
|
+
(nid, round(s, 4)) for nid, s in top_bridges
|
|
153
|
+
],
|
|
154
|
+
"community_labels": labels,
|
|
155
|
+
}
|
|
156
|
+
except Exception as exc:
|
|
157
|
+
logger.debug("GraphAnalyzer.compute_and_store failed: %s", exc)
|
|
158
|
+
return {
|
|
159
|
+
"node_count": 0,
|
|
160
|
+
"edge_count": 0,
|
|
161
|
+
"community_count": 0,
|
|
162
|
+
"top_5_nodes": [],
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
def compute_pagerank(
|
|
166
|
+
self,
|
|
167
|
+
graph: Any = None,
|
|
168
|
+
profile_id: str = "",
|
|
169
|
+
alpha: float = 0.85,
|
|
170
|
+
) -> dict[str, float]:
|
|
171
|
+
"""Compute PageRank using networkx.
|
|
172
|
+
|
|
173
|
+
alpha = damping factor (0.85 is standard).
|
|
174
|
+
"""
|
|
175
|
+
import networkx as nx
|
|
176
|
+
|
|
177
|
+
if graph is None:
|
|
178
|
+
graph = self._build_networkx_graph(profile_id)
|
|
179
|
+
if graph.number_of_nodes() == 0:
|
|
180
|
+
return {}
|
|
181
|
+
try:
|
|
182
|
+
return nx.pagerank(graph, alpha=alpha, weight="weight")
|
|
183
|
+
except nx.PowerIterationFailedConvergence:
|
|
184
|
+
return nx.pagerank(graph, alpha=alpha, weight=None)
|
|
185
|
+
|
|
186
|
+
def detect_communities(
|
|
187
|
+
self,
|
|
188
|
+
graph: Any = None,
|
|
189
|
+
profile_id: str = "",
|
|
190
|
+
) -> dict[str, int]:
|
|
191
|
+
"""Detect communities via Label Propagation.
|
|
192
|
+
|
|
193
|
+
O(m) where m = edges (fast), no parameter tuning needed.
|
|
194
|
+
"""
|
|
195
|
+
import networkx as nx
|
|
196
|
+
from networkx.algorithms.community import (
|
|
197
|
+
label_propagation_communities,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
if graph is None:
|
|
201
|
+
graph = self._build_networkx_graph(profile_id)
|
|
202
|
+
if graph.number_of_nodes() == 0:
|
|
203
|
+
return {}
|
|
204
|
+
|
|
205
|
+
# Label propagation needs undirected graph
|
|
206
|
+
undirected = graph.to_undirected()
|
|
207
|
+
communities_gen = label_propagation_communities(undirected)
|
|
208
|
+
result: dict[str, int] = {}
|
|
209
|
+
for comm_id, community in enumerate(communities_gen):
|
|
210
|
+
for node in community:
|
|
211
|
+
result[node] = comm_id
|
|
212
|
+
return result
|
|
213
|
+
|
|
214
|
+
# ── v3.4.1: Leiden Community Detection ────────────────────────
|
|
215
|
+
|
|
216
|
+
def detect_communities_leiden(
|
|
217
|
+
self,
|
|
218
|
+
graph: Any = None,
|
|
219
|
+
profile_id: str = "",
|
|
220
|
+
resolution: float = 1.0,
|
|
221
|
+
) -> dict[str, int]:
|
|
222
|
+
"""Leiden community detection (higher quality than Label Propagation).
|
|
223
|
+
|
|
224
|
+
Falls back to detect_communities() (Label Propagation) if
|
|
225
|
+
leidenalg or igraph are not installed.
|
|
226
|
+
"""
|
|
227
|
+
if graph is None:
|
|
228
|
+
graph = self._build_networkx_graph(profile_id)
|
|
229
|
+
if graph.number_of_nodes() == 0:
|
|
230
|
+
return {}
|
|
231
|
+
|
|
232
|
+
try:
|
|
233
|
+
import leidenalg
|
|
234
|
+
import igraph
|
|
235
|
+
except ImportError:
|
|
236
|
+
logger.info(
|
|
237
|
+
"leidenalg not installed, using Label Propagation fallback",
|
|
238
|
+
)
|
|
239
|
+
return self.detect_communities(graph, profile_id)
|
|
240
|
+
|
|
241
|
+
# Convert DiGraph -> undirected -> igraph
|
|
242
|
+
undirected = graph.to_undirected()
|
|
243
|
+
node_list = list(undirected.nodes())
|
|
244
|
+
node_index = {n: i for i, n in enumerate(node_list)}
|
|
245
|
+
|
|
246
|
+
ig = igraph.Graph(n=len(node_list), directed=False)
|
|
247
|
+
edges = []
|
|
248
|
+
weights = []
|
|
249
|
+
for u, v in undirected.edges():
|
|
250
|
+
if u in node_index and v in node_index:
|
|
251
|
+
edges.append((node_index[u], node_index[v]))
|
|
252
|
+
weights.append(undirected[u][v].get("weight", 1.0))
|
|
253
|
+
|
|
254
|
+
ig.add_edges(edges)
|
|
255
|
+
ig.es["weight"] = weights
|
|
256
|
+
ig.simplify(combine_edges={"weight": "max"})
|
|
257
|
+
|
|
258
|
+
partition = leidenalg.find_partition(
|
|
259
|
+
ig,
|
|
260
|
+
leidenalg.RBConfigurationVertexPartition,
|
|
261
|
+
resolution_parameter=resolution,
|
|
262
|
+
weights="weight",
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
result: dict[str, int] = {}
|
|
266
|
+
for idx, comm_id in enumerate(partition.membership):
|
|
267
|
+
result[node_list[idx]] = comm_id
|
|
268
|
+
|
|
269
|
+
logger.info(
|
|
270
|
+
"Leiden detected %d communities (resolution=%.1f)",
|
|
271
|
+
len(set(result.values())), resolution,
|
|
272
|
+
)
|
|
273
|
+
return result
|
|
274
|
+
|
|
275
|
+
# ── v3.4.1: TF-IDF Community Labels ─────────────────────────
|
|
276
|
+
|
|
277
|
+
def compute_community_labels(
|
|
278
|
+
self,
|
|
279
|
+
profile_id: str,
|
|
280
|
+
communities: dict[str, int],
|
|
281
|
+
) -> dict[int, str]:
|
|
282
|
+
"""Generate human-readable labels via TF-IDF on fact content.
|
|
283
|
+
|
|
284
|
+
Returns dict mapping community_id to label string.
|
|
285
|
+
Labels stored in config table for API access.
|
|
286
|
+
"""
|
|
287
|
+
if not communities:
|
|
288
|
+
return {}
|
|
289
|
+
|
|
290
|
+
# Group fact_ids by community
|
|
291
|
+
comm_facts: dict[int, list[str]] = defaultdict(list)
|
|
292
|
+
for fact_id, comm_id in communities.items():
|
|
293
|
+
comm_facts[comm_id].append(fact_id)
|
|
294
|
+
|
|
295
|
+
stopwords = frozenset({
|
|
296
|
+
"the", "a", "an", "is", "was", "were", "are", "be", "been",
|
|
297
|
+
"being", "have", "has", "had", "do", "does", "did", "will",
|
|
298
|
+
"would", "could", "should", "may", "might", "shall", "can",
|
|
299
|
+
"to", "of", "in", "for", "on", "with", "at", "by", "from",
|
|
300
|
+
"as", "into", "through", "during", "before", "after", "above",
|
|
301
|
+
"below", "between", "and", "but", "or", "not", "no", "nor",
|
|
302
|
+
"so", "yet", "both", "either", "neither", "this", "that",
|
|
303
|
+
"these", "those", "it", "its", "they", "them", "their",
|
|
304
|
+
"he", "she", "his", "her", "we", "our", "you", "your",
|
|
305
|
+
"i", "my", "me",
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
# Fetch content for each community
|
|
309
|
+
tf_per_comm: dict[int, Counter] = {}
|
|
310
|
+
for comm_id, fact_ids in comm_facts.items():
|
|
311
|
+
placeholders = ",".join("?" * len(fact_ids))
|
|
312
|
+
sql = (
|
|
313
|
+
"SELECT content FROM atomic_facts WHERE fact_id IN ("
|
|
314
|
+
+ placeholders
|
|
315
|
+
+ ") AND profile_id = ?"
|
|
316
|
+
)
|
|
317
|
+
try:
|
|
318
|
+
rows = self._db.execute(sql, (*fact_ids, profile_id))
|
|
319
|
+
texts = [dict(r).get("content", "") for r in rows]
|
|
320
|
+
except Exception:
|
|
321
|
+
texts = []
|
|
322
|
+
|
|
323
|
+
tokens: list[str] = []
|
|
324
|
+
for text in texts:
|
|
325
|
+
for word in text.lower().split():
|
|
326
|
+
w = word.strip(".,;:!?\"'()[]{}")
|
|
327
|
+
if len(w) > 2 and w not in stopwords:
|
|
328
|
+
tokens.append(w)
|
|
329
|
+
tf_per_comm[comm_id] = Counter(tokens)
|
|
330
|
+
|
|
331
|
+
num_communities = len(comm_facts)
|
|
332
|
+
labels: dict[int, str] = {}
|
|
333
|
+
|
|
334
|
+
if num_communities == 1:
|
|
335
|
+
# Single community: use raw term frequency
|
|
336
|
+
for comm_id, tf in tf_per_comm.items():
|
|
337
|
+
top = [w for w, _ in tf.most_common(3)]
|
|
338
|
+
labels[comm_id] = ", ".join(top) if top else f"Community {comm_id}"
|
|
339
|
+
else:
|
|
340
|
+
# Compute IDF across communities
|
|
341
|
+
doc_freq: Counter = Counter()
|
|
342
|
+
for tf in tf_per_comm.values():
|
|
343
|
+
for term in tf:
|
|
344
|
+
doc_freq[term] += 1
|
|
345
|
+
|
|
346
|
+
for comm_id, tf in tf_per_comm.items():
|
|
347
|
+
scored = []
|
|
348
|
+
for term, count in tf.items():
|
|
349
|
+
idf = log(1 + num_communities / (1 + doc_freq[term]))
|
|
350
|
+
scored.append((term, count * idf))
|
|
351
|
+
scored.sort(key=lambda x: x[1], reverse=True)
|
|
352
|
+
top = [w for w, _ in scored[:3]]
|
|
353
|
+
labels[comm_id] = ", ".join(top) if top else f"Community {comm_id}"
|
|
354
|
+
|
|
355
|
+
# Store in config table
|
|
356
|
+
try:
|
|
357
|
+
key = "community_labels_" + profile_id
|
|
358
|
+
value = json.dumps(labels)
|
|
359
|
+
self._db.execute(
|
|
360
|
+
"INSERT OR REPLACE INTO config (key, value, updated_at) "
|
|
361
|
+
"VALUES (?, ?, datetime('now'))",
|
|
362
|
+
(key, value),
|
|
363
|
+
)
|
|
364
|
+
except Exception as exc:
|
|
365
|
+
logger.warning("Failed to store community labels: %s", exc)
|
|
366
|
+
|
|
367
|
+
return labels
|
|
368
|
+
|
|
369
|
+
# ── v3.4.1: Bridge Score Detection ───────────────────────────
|
|
370
|
+
|
|
371
|
+
def compute_bridge_scores(self, graph: Any) -> dict[str, float]:
|
|
372
|
+
"""Identify bridge nodes via betweenness centrality.
|
|
373
|
+
|
|
374
|
+
Returns dict mapping node_id to bridge_score (0.0 to 1.0).
|
|
375
|
+
NOT persisted to DB (no column exists) -- used in summary only.
|
|
376
|
+
"""
|
|
377
|
+
import networkx as nx
|
|
378
|
+
|
|
379
|
+
if graph.number_of_nodes() <= 2:
|
|
380
|
+
return {}
|
|
381
|
+
return nx.betweenness_centrality(
|
|
382
|
+
graph, weight="weight", normalized=True,
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
def _compute_degree_centrality(
|
|
386
|
+
self, graph: Any,
|
|
387
|
+
) -> dict[str, float]:
|
|
388
|
+
"""Degree centrality: fraction of nodes each node connects to."""
|
|
389
|
+
import networkx as nx
|
|
390
|
+
|
|
391
|
+
if graph.number_of_nodes() <= 1:
|
|
392
|
+
return {n: 0.0 for n in graph.nodes()}
|
|
393
|
+
return nx.degree_centrality(graph)
|
|
394
|
+
|
|
395
|
+
def _build_networkx_graph(self, profile_id: str) -> Any:
|
|
396
|
+
"""Build networkx DiGraph from BOTH graph_edges + association_edges."""
|
|
397
|
+
import networkx as nx
|
|
398
|
+
|
|
399
|
+
g = nx.DiGraph()
|
|
400
|
+
|
|
401
|
+
# graph_edges
|
|
402
|
+
try:
|
|
403
|
+
rows = self._db.execute(
|
|
404
|
+
"SELECT source_id, target_id, weight, edge_type "
|
|
405
|
+
"FROM graph_edges WHERE profile_id = ?",
|
|
406
|
+
(profile_id,),
|
|
407
|
+
)
|
|
408
|
+
for row in rows:
|
|
409
|
+
d = dict(row)
|
|
410
|
+
g.add_edge(
|
|
411
|
+
d["source_id"], d["target_id"],
|
|
412
|
+
weight=d["weight"], edge_type=d["edge_type"],
|
|
413
|
+
)
|
|
414
|
+
except Exception as exc:
|
|
415
|
+
logger.debug("graph_edges read failed: %s", exc)
|
|
416
|
+
|
|
417
|
+
# association_edges
|
|
418
|
+
try:
|
|
419
|
+
rows = self._db.execute(
|
|
420
|
+
"SELECT source_fact_id, target_fact_id, weight, "
|
|
421
|
+
" association_type "
|
|
422
|
+
"FROM association_edges WHERE profile_id = ?",
|
|
423
|
+
(profile_id,),
|
|
424
|
+
)
|
|
425
|
+
for row in rows:
|
|
426
|
+
d = dict(row)
|
|
427
|
+
src, tgt = d["source_fact_id"], d["target_fact_id"]
|
|
428
|
+
if g.has_edge(src, tgt):
|
|
429
|
+
existing_w = g[src][tgt].get("weight", 0)
|
|
430
|
+
if d["weight"] > existing_w:
|
|
431
|
+
g[src][tgt]["weight"] = d["weight"]
|
|
432
|
+
else:
|
|
433
|
+
g.add_edge(
|
|
434
|
+
src, tgt,
|
|
435
|
+
weight=d["weight"],
|
|
436
|
+
edge_type=d["association_type"],
|
|
437
|
+
)
|
|
438
|
+
except Exception as exc:
|
|
439
|
+
logger.debug("association_edges read failed: %s", exc)
|
|
440
|
+
|
|
441
|
+
return g
|