memorymaster 3.15.1__tar.gz → 3.17.0__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.
- {memorymaster-3.15.1/memorymaster.egg-info → memorymaster-3.17.0}/PKG-INFO +1 -1
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/cli.py +8 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/cli_handlers_basic.py +23 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/config.py +25 -5
- memorymaster-3.17.0/memorymaster/jobs/daydream_ingest.py +331 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/retrieval.py +74 -4
- {memorymaster-3.15.1 → memorymaster-3.17.0/memorymaster.egg-info}/PKG-INFO +1 -1
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster.egg-info/SOURCES.txt +4 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/pyproject.toml +1 -1
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_config.py +7 -1
- memorymaster-3.17.0/tests/test_daydream_ingest.py +123 -0
- memorymaster-3.17.0/tests/test_retrieval_rrf_tiebreaker.py +84 -0
- memorymaster-3.17.0/tests/test_retrieval_weights.py +69 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/LICENSE +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/README.md +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/artifacts/bm25-per-field-eval-harness.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/benchmarks/longmemeval_runner.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/benchmarks/longmemeval_vector_runner.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/benchmarks/perf_smoke.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/__init__.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/__main__.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/_storage_lifecycle.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/_storage_read.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/_storage_schema.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/_storage_shared.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/_storage_sources.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/_storage_write_claims.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/access_control.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/action_exporters.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/action_extractor.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/atlas_claim_extractor.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/atlas_contract.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/auto_extractor.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/auto_resolver.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/candidate_dedupe.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/claim_edges.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/claim_verifier.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/cli_handlers_curation.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/cli_helpers.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/closets.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/config_templates/claude-md-append.md +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/config_templates/codex-agents-md-append.md +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/config_templates/hooks/memorymaster-auto-ingest.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/config_templates/hooks/memorymaster-classify.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/config_templates/hooks/memorymaster-dream-sync.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/config_templates/hooks/memorymaster-precompact.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/config_templates/hooks/memorymaster-recall.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/config_templates/hooks/memorymaster-session-start.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/config_templates/hooks/memorymaster-steward-cycle.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/config_templates/hooks/memorymaster-validate-wiki.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/conflict_resolver.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/connectors/__init__.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/connectors/whatsapp.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/context_hook.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/context_optimizer.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/daily_notes.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/dashboard.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/db_merge.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/dream_bridge.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/embeddings.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/entity_extractor.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/entity_graph.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/entity_registry.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/federated_graphify.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/feedback.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/graph_store.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/hook_log.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/jobs/__init__.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/jobs/calibration.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/jobs/compact_summaries.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/jobs/compactor.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/jobs/decay.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/jobs/dedup.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/jobs/deterministic.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/jobs/entity_graph_export.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/jobs/extractor.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/jobs/staleness.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/jobs/validator.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/key_rotator.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/lifecycle.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/llm_provider.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/llm_rerank.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/llm_steward.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/mcp_server.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/mcp_usage.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/media_processing.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/media_providers.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/metrics_exporter.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/models.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/observability.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/operator.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/operator_queue.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/plugins.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/policy.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/postgres_store.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/qdrant_backend.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/qdrant_recall_fallback.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/qmd_bridge.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/query_classifier.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/query_expansion.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/recall_fusion.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/recall_tokenizer.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/retry.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/review.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/rl_trainer.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/scheduler.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/schema.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/schema.sql +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/schema_postgres.sql +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/scope_utils.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/security.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/service.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/session_tracker.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/setup_hooks.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/skill_evolver.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/snapshot.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/steward.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/steward_classifier.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/steward_features.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/storage.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/store_factory.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/transcript_miner.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/turn_schema.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/vault_bases.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/vault_curator.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/vault_exporter.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/vault_linter.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/vault_log.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/vault_query_capture.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/vault_synthesis.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/verbatim_recall.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/verbatim_store.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/webhook.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/wiki_engine.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/wiki_freshness.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/wiki_similarity.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/wiki_suggest.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster/wiki_validate.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster.egg-info/dependency_links.txt +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster.egg-info/entry_points.txt +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster.egg-info/requires.txt +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/memorymaster.egg-info/top_level.txt +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/agg_recall_latency.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/alert_operator_metrics.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/audit_dedupe_precision.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/autoresearch_daemon.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/backfill_entity_extraction.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/backfill_graph_store.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/backfill_stop_hook_citations.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/backtest_steward_classifier.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/build_steward_training_set.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/check_hook_template_drift.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/claude_to_turns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/codex_live_to_turns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/compaction_edge_cases.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/compaction_trace_report.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/compaction_trace_validate.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/confusion_matrix_eval.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/conversation_importer.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/conversation_to_turns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/e2e_operator.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/email_live_to_turns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/eval_bm25_sweep.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/eval_classify_f1.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/eval_memorymaster.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/eval_recall_precision_at_5.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/eval_recall_quality.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/eval_steward_pareto.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/eval_verbatim_recall.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/expand_recall_eval.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/generate_drill_signoff.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/git_to_turns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/github_live_to_turns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/gitnexus_to_claims.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/grid_recall_weights.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/index_claims_to_qdrant.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/ingest_planning_docs.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/jira_live_to_turns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/label_prompts_with_judge.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/llm_benchmark.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/measure_dedupe_thresholds.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/merge_scope_variants.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/messages_to_turns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/operator_metrics.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/precompute_candidates.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/recurring_incident_drill.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/release_readiness.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/run_codex_autologger.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/run_incident_drill.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/scheduled_ingest.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/setup-hooks.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/slack_live_to_turns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/sync_hook_templates.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/tickets_to_turns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/train_steward_classifier.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/scripts/webhook_to_turns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/setup.cfg +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/bench_longmemeval.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/conftest.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/integration/test_extract_llm_ollama_live.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_access_control.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_action_exporters.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_action_extractor.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_atlas_claim_extractor.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_atlas_contract.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_atlas_source_schema.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_auto_extractor.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_auto_ingest_hook_citations.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_auto_ingest_hook_schema.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_auto_resolver.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_auto_validate.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_bm25_per_field.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_calibration.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_calibration_priors_applied.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_candidate_dedupe.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_claim_edges.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_claim_links.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_claim_type_ranking.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_classify_hook_f1.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_classify_hook_latency.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_claude_to_turns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_cli_dry_run.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_cli_json_flag.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_cli_ready.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_cli_review_queue.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_cli_subcommands.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_closets.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_closets_recall_integration.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_compact_summaries.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_compact_summaries_sensitivity.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_compaction_trace.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_compactor_artifact_order.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_conflict_resolver.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_confusion_matrix_eval.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_connection_retry.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_connectors.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_context_hook.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_context_optimizer.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_context_optimizer_provider.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_conversation_to_turns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_dashboard.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_dashboard_coverage.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_dashboard_latency.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_dashboard_lineage.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_dashboard_review_queue.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_db_merge_confidence_conflict.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_db_merge_coverage_v2.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_decay_coverage.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_decay_respects_pinned.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_dedup.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_dedup_cli.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_dedup_conflict_disambiguation.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_deterministic_predicates.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_dream_bridge_coverage_v2.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_dream_bridge_sensitivity.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_embeddings_coverage.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_entity_extractor.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_entity_extractor_llm.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_entity_graph.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_entity_graph_export.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_entity_new_kinds.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_entity_regex_v3.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_entity_registry.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_eval_harness.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_events_schema.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_extract_llm_ollama.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_federated_graphify_mcp.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_federated_query_safety.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_feedback.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_fts5_search.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_graph_distance.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_graph_store.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_handler_regressions.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_hook_env_isolation.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_human_id.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_incident_drill_runner.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_integration_workflows.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_key_rotator.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_lifecycle.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_lifecycle_supersede_invariant.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_llm_fallback.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_llm_provider_claude_cli.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_llm_provider_key_rotation.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_llm_steward_coverage.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_llm_steward_key_rotation.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_mcp_filter_bypass.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_mcp_helpers.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_mcp_rate_limit.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_mcp_server_validation.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_mcp_usage.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_media_processing.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_meta_decisions.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_metrics_exporter.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_observability.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_obsidian_mind_patterns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_operator.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_operator_queue.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_perf_smoke_config.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_plugins.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_policy_coverage.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_policy_mode_env.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_postgres_parity.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_qdrant_backend.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_qmd_bridge.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_query_classifier.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_query_expansion.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_recall_entity_fanout.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_recall_fusion.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_recall_latency.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_recall_precision_at_5.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_recall_tokenizer.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_recall_vector_fallback.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_reliability_hardening.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_resolvers_concurrent_supersede.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_retrieval_profile.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_review.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_rl_trainer.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_rrf_auto_gate.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_scheduler.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_schema.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_scope_boost.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_scope_utils.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_security_access.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_security_patterns.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_sensitivity_filter_adversarial.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_sensitivity_filter_adversarial_v2.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_sensitivity_filter_t07.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_service_coverage.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_session_tracker.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_snapshot.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_snapshot_roundtrip.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_sqlite_core.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_staleness.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_stealth_mode.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_steward.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_steward_classifier.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_steward_features.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_steward_features_v3.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_steward_resolution_parity.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_storage_parity.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_store_factory.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_tenant_isolation.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_turn_schema.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_two_pass_recall.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_v311_fixes.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_v313_e2e.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_v313_run_cycle_dedupe.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_v390_e2e.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_v391_strict_warnings.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_vault_exporter.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_vault_linter_orphan.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_vector_search.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_verbatim_dedup.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_verbatim_recall.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_verbatim_store.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_verbatim_store_qdrant.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_webhook.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_whatsapp_importer.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_wiki_autopromote.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_wiki_binding.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_wiki_engine_idempotency.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_wiki_explored_and_contradictions.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_wiki_freshness.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_wiki_similarity_multiscope.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_wiki_suggest.py +0 -0
- {memorymaster-3.15.1 → memorymaster-3.17.0}/tests/test_wiki_validate_cli.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memorymaster
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.17.0
|
|
4
4
|
Summary: Production-grade memory reliability system for AI coding agents. Lifecycle-managed claims with citations, conflict detection, steward governance, and MCP integration.
|
|
5
5
|
Author: wolverin0
|
|
6
6
|
License: MIT
|
|
@@ -23,6 +23,7 @@ from memorymaster.cli_handlers_curation import COMMAND_HANDLERS
|
|
|
23
23
|
from memorymaster.cli_handlers_basic import (
|
|
24
24
|
_handle_decay,
|
|
25
25
|
_handle_entity_graph_export,
|
|
26
|
+
_handle_ingest_daydream,
|
|
26
27
|
_handle_recompute_confidence_priors,
|
|
27
28
|
_handle_wiki_suggest_links,
|
|
28
29
|
handle_mcp_usage_report,
|
|
@@ -33,6 +34,7 @@ COMMAND_HANDLERS["entity-graph-export"] = _handle_entity_graph_export
|
|
|
33
34
|
COMMAND_HANDLERS["recompute-confidence-priors"] = _handle_recompute_confidence_priors
|
|
34
35
|
COMMAND_HANDLERS["wiki-suggest-links"] = _handle_wiki_suggest_links
|
|
35
36
|
COMMAND_HANDLERS["decay"] = _handle_decay
|
|
37
|
+
COMMAND_HANDLERS["ingest-daydream"] = _handle_ingest_daydream
|
|
36
38
|
COMMAND_HANDLERS["mcp-usage-report"] = (
|
|
37
39
|
lambda args, service, parser, effective_db: handle_mcp_usage_report(args, effective_db)
|
|
38
40
|
)
|
|
@@ -66,6 +68,12 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
66
68
|
ingest.add_argument("--valid-from", default=None, help="ISO-8601 timestamp: start of the claim validity window")
|
|
67
69
|
ingest.add_argument("--valid-until", default=None, help="ISO-8601 timestamp: end of the validity window (omit if still current)")
|
|
68
70
|
|
|
71
|
+
ingest_daydream = sub.add_parser("ingest-daydream", help="Ingest daydream insights as candidate hypothesis claims")
|
|
72
|
+
ingest_daydream.add_argument("insights_dir", help="Daydreams directory containing insight JSON or Markdown files")
|
|
73
|
+
ingest_daydream.add_argument("--min-score", type=float, default=7.0, help="Minimum average score to ingest")
|
|
74
|
+
ingest_daydream.add_argument("--scope", default="user", help="Claim scope (default: user)")
|
|
75
|
+
ingest_daydream.add_argument("--dry-run", action="store_true", help="Preview ingest without writing claims")
|
|
76
|
+
|
|
69
77
|
import_whatsapp = sub.add_parser("import-whatsapp", help="Import WhatsApp messages from a wacli JSON/JSONL export")
|
|
70
78
|
import_whatsapp.add_argument("--input", required=True, help="Path to wacli JSON or JSONL export")
|
|
71
79
|
import_whatsapp.add_argument("--display-name", default="WhatsApp", help="External source display name")
|
|
@@ -324,6 +324,29 @@ def _handle_ingest(args: argparse.Namespace, service, parser: argparse.ArgumentP
|
|
|
324
324
|
return 0
|
|
325
325
|
|
|
326
326
|
|
|
327
|
+
def _handle_ingest_daydream(args: argparse.Namespace, service, parser: argparse.ArgumentParser, effective_db: str) -> int:
|
|
328
|
+
from memorymaster.jobs.daydream_ingest import ingest_insights
|
|
329
|
+
|
|
330
|
+
t0 = time.perf_counter()
|
|
331
|
+
result = ingest_insights(
|
|
332
|
+
service,
|
|
333
|
+
Path(args.insights_dir),
|
|
334
|
+
min_score=args.min_score,
|
|
335
|
+
scope=args.scope,
|
|
336
|
+
dry_run=args.dry_run,
|
|
337
|
+
)
|
|
338
|
+
elapsed_ms = (time.perf_counter() - t0) * 1000
|
|
339
|
+
if args.json_output:
|
|
340
|
+
print(_json_envelope(result, query_ms=elapsed_ms))
|
|
341
|
+
else:
|
|
342
|
+
tag = " [DRY RUN]" if args.dry_run else ""
|
|
343
|
+
print(
|
|
344
|
+
f"ingest-daydream{tag}: ingested={result['ingested']} "
|
|
345
|
+
f"skipped={result['skipped']} errors={len(result['errors'])}"
|
|
346
|
+
)
|
|
347
|
+
return 0
|
|
348
|
+
|
|
349
|
+
|
|
327
350
|
def _handle_import_whatsapp(args: argparse.Namespace, service, parser: argparse.ArgumentParser, effective_db: str) -> int:
|
|
328
351
|
from memorymaster.atlas_contract import atlas_meta
|
|
329
352
|
from memorymaster.connectors.whatsapp import import_wacli_json
|
|
@@ -8,7 +8,11 @@ Environment variables
|
|
|
8
8
|
---------------------
|
|
9
9
|
MEMORYMASTER_RETRIEVAL_WEIGHTS
|
|
10
10
|
Comma-separated floats for hybrid ranking: lexical,confidence,freshness,vector.
|
|
11
|
-
Default: ``0.
|
|
11
|
+
Default: ``0.30,0.20,0.10,0.40``
|
|
12
|
+
|
|
13
|
+
MEMORYMASTER_W_LEX, MEMORYMASTER_W_CONF, MEMORYMASTER_W_FRESH, MEMORYMASTER_W_VEC
|
|
14
|
+
Individual overrides for the four hybrid ranking weights. These take
|
|
15
|
+
precedence over ``MEMORYMASTER_RETRIEVAL_WEIGHTS`` when set.
|
|
12
16
|
|
|
13
17
|
MEMORYMASTER_RETRIEVAL_WEIGHTS_NO_VECTOR
|
|
14
18
|
Weights when vector search is disabled: lexical,confidence,freshness.
|
|
@@ -55,6 +59,14 @@ MEMORYMASTER_LLM_RERANK
|
|
|
55
59
|
Enable Gemini cross-encoder reranking over the top retrieval candidates.
|
|
56
60
|
Default: ``0``
|
|
57
61
|
|
|
62
|
+
MEMORYMASTER_RRF_TIEBREAKER
|
|
63
|
+
Enable RRF near-tie reordering after linear retrieval ranking.
|
|
64
|
+
Default: ``0``
|
|
65
|
+
|
|
66
|
+
MEMORYMASTER_RRF_TIEBREAKER_THRESHOLD
|
|
67
|
+
Maximum adjacent score gap considered a near tie.
|
|
68
|
+
Default: ``0.01``
|
|
69
|
+
|
|
58
70
|
MEMORYMASTER_CONFIG_FILE
|
|
59
71
|
Path to a JSON config file. Keys match attribute names on ``Config``.
|
|
60
72
|
"""
|
|
@@ -159,10 +171,10 @@ class Config:
|
|
|
159
171
|
"""Immutable configuration for tunable MemoryMaster constants."""
|
|
160
172
|
|
|
161
173
|
# --- Retrieval ranking weights (hybrid mode with vector) ---
|
|
162
|
-
retrieval_weight_lexical: float = 0.
|
|
163
|
-
retrieval_weight_confidence: float = 0.
|
|
164
|
-
retrieval_weight_freshness: float = 0.
|
|
165
|
-
retrieval_weight_vector: float = 0.
|
|
174
|
+
retrieval_weight_lexical: float = 0.30
|
|
175
|
+
retrieval_weight_confidence: float = 0.20
|
|
176
|
+
retrieval_weight_freshness: float = 0.10
|
|
177
|
+
retrieval_weight_vector: float = 0.40
|
|
166
178
|
|
|
167
179
|
# --- Retrieval ranking weights (hybrid mode without vector) ---
|
|
168
180
|
retrieval_weight_lexical_no_vector: float = 0.55
|
|
@@ -197,6 +209,8 @@ class Config:
|
|
|
197
209
|
pinned_bonus: float = 0.03
|
|
198
210
|
session_diversity_cap: int = 3
|
|
199
211
|
llm_rerank: bool = False
|
|
212
|
+
rrf_tiebreaker_enabled: bool = False
|
|
213
|
+
rrf_tiebreaker_threshold: float = 0.01
|
|
200
214
|
|
|
201
215
|
# --- Initial confidence priors calibrated from validator outcomes ---
|
|
202
216
|
default_initial_confidence: float = DEFAULT_INITIAL_CONFIDENCE
|
|
@@ -310,6 +324,10 @@ def load_config(config_path: str | Path | None = None) -> Config:
|
|
|
310
324
|
"retrieval_weight_freshness",
|
|
311
325
|
"retrieval_weight_vector",
|
|
312
326
|
])
|
|
327
|
+
_apply_env_float(overrides, "MEMORYMASTER_W_LEX", "retrieval_weight_lexical")
|
|
328
|
+
_apply_env_float(overrides, "MEMORYMASTER_W_CONF", "retrieval_weight_confidence")
|
|
329
|
+
_apply_env_float(overrides, "MEMORYMASTER_W_FRESH", "retrieval_weight_freshness")
|
|
330
|
+
_apply_env_float(overrides, "MEMORYMASTER_W_VEC", "retrieval_weight_vector")
|
|
313
331
|
_apply_env_floats(overrides, "MEMORYMASTER_RETRIEVAL_WEIGHTS_NO_VECTOR", 3, [
|
|
314
332
|
"retrieval_weight_lexical_no_vector",
|
|
315
333
|
"retrieval_weight_confidence_no_vector",
|
|
@@ -343,6 +361,8 @@ def load_config(config_path: str | Path | None = None) -> Config:
|
|
|
343
361
|
_apply_env_float(overrides, "MEMORYMASTER_PINNED_BONUS", "pinned_bonus")
|
|
344
362
|
_apply_env_int(overrides, "MEMORYMASTER_SESSION_DIVERSITY_CAP", "session_diversity_cap")
|
|
345
363
|
_apply_env_bool(overrides, "MEMORYMASTER_LLM_RERANK", "llm_rerank")
|
|
364
|
+
_apply_env_bool(overrides, "MEMORYMASTER_RRF_TIEBREAKER", "rrf_tiebreaker_enabled")
|
|
365
|
+
_apply_env_float(overrides, "MEMORYMASTER_RRF_TIEBREAKER_THRESHOLD", "rrf_tiebreaker_threshold")
|
|
346
366
|
|
|
347
367
|
# Filter to only valid Config fields
|
|
348
368
|
valid_fields = {f.name for f in Config.__dataclass_fields__.values()}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
import re
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from memorymaster.models import CitationInput
|
|
11
|
+
from memorymaster.service import MemoryService
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(slots=True)
|
|
17
|
+
class _DaydreamInsight:
|
|
18
|
+
title: str
|
|
19
|
+
connection: str
|
|
20
|
+
synthesis: str
|
|
21
|
+
implication: str
|
|
22
|
+
average: float | None
|
|
23
|
+
date: str
|
|
24
|
+
references: list[dict[str, str]]
|
|
25
|
+
path: Path
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def ingest_insights(
|
|
29
|
+
service: MemoryService,
|
|
30
|
+
insights_dir: Path,
|
|
31
|
+
*,
|
|
32
|
+
min_score: float = 7.0,
|
|
33
|
+
scope: str = "user",
|
|
34
|
+
dry_run: bool = False,
|
|
35
|
+
) -> dict:
|
|
36
|
+
"""Ingest accepted daydream insights as candidate hypothesis claims."""
|
|
37
|
+
root = Path(insights_dir)
|
|
38
|
+
result: dict[str, Any] = {"ingested": 0, "skipped": 0, "errors": []}
|
|
39
|
+
if not root.exists() or not root.is_dir():
|
|
40
|
+
raise ValueError(f"insights_dir does not exist or is not a directory: {root}")
|
|
41
|
+
|
|
42
|
+
for path in _iter_insight_files(root):
|
|
43
|
+
insight = _load_insight(path)
|
|
44
|
+
if insight is None:
|
|
45
|
+
result["skipped"] += 1
|
|
46
|
+
result["errors"].append(f"{path}: could not parse daydream insight")
|
|
47
|
+
continue
|
|
48
|
+
|
|
49
|
+
if insight.average is None or insight.average < min_score:
|
|
50
|
+
result["skipped"] += 1
|
|
51
|
+
continue
|
|
52
|
+
|
|
53
|
+
idempotency_key = _idempotency_key(insight)
|
|
54
|
+
if _claim_exists(service, idempotency_key):
|
|
55
|
+
result["skipped"] += 1
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
if dry_run:
|
|
59
|
+
result["ingested"] += 1
|
|
60
|
+
continue
|
|
61
|
+
|
|
62
|
+
claim = service.ingest(
|
|
63
|
+
text=insight.synthesis,
|
|
64
|
+
citations=_citations_for(insight),
|
|
65
|
+
idempotency_key=idempotency_key,
|
|
66
|
+
claim_type="hypothesis",
|
|
67
|
+
subject=insight.title or _subject_from_connection(insight.connection),
|
|
68
|
+
scope=scope,
|
|
69
|
+
volatility="medium",
|
|
70
|
+
confidence=0.5,
|
|
71
|
+
source_agent="daydream",
|
|
72
|
+
)
|
|
73
|
+
if claim.idempotency_key == idempotency_key:
|
|
74
|
+
result["ingested"] += 1
|
|
75
|
+
else:
|
|
76
|
+
result["skipped"] += 1
|
|
77
|
+
|
|
78
|
+
return result
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _iter_insight_files(root: Path) -> list[Path]:
|
|
82
|
+
files = [path for path in root.rglob("*.json") if path.is_file()]
|
|
83
|
+
files.extend(
|
|
84
|
+
path
|
|
85
|
+
for path in root.rglob("*.md")
|
|
86
|
+
if path.is_file() and "digests" not in {part.lower() for part in path.parts}
|
|
87
|
+
)
|
|
88
|
+
return sorted(files)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _load_insight(path: Path) -> _DaydreamInsight | None:
|
|
92
|
+
try:
|
|
93
|
+
if path.suffix.lower() == ".json":
|
|
94
|
+
return _load_json_insight(path)
|
|
95
|
+
if path.suffix.lower() == ".md":
|
|
96
|
+
return _load_markdown_insight(path)
|
|
97
|
+
except Exception as exc:
|
|
98
|
+
logger.warning("Skipping daydream insight %s: %s", path, exc)
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _load_json_insight(path: Path) -> _DaydreamInsight | None:
|
|
103
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
104
|
+
if isinstance(data, list):
|
|
105
|
+
logger.warning("Skipping daydream manifest-like JSON %s", path)
|
|
106
|
+
return None
|
|
107
|
+
if not isinstance(data, dict):
|
|
108
|
+
return None
|
|
109
|
+
|
|
110
|
+
metadata = _dict_value(data.get("metadata"))
|
|
111
|
+
scores = _dict_value(metadata.get("scores"))
|
|
112
|
+
average = _float_value(
|
|
113
|
+
data.get("avg_score")
|
|
114
|
+
or data.get("average")
|
|
115
|
+
or scores.get("average")
|
|
116
|
+
or scores.get("avg_score")
|
|
117
|
+
)
|
|
118
|
+
title = _text_value(data.get("title") or data.get("suggested_title"))
|
|
119
|
+
connection = _text_value(data.get("connection"))
|
|
120
|
+
synthesis = _text_value(data.get("synthesis"))
|
|
121
|
+
implication = _text_value(data.get("implication"))
|
|
122
|
+
if not synthesis:
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
references = _references_from_json(data, metadata)
|
|
126
|
+
date = _normalize_date(
|
|
127
|
+
data.get("date")
|
|
128
|
+
or data.get("created_date")
|
|
129
|
+
or metadata.get("date")
|
|
130
|
+
or metadata.get("created_date")
|
|
131
|
+
or _date_from_filename(path)
|
|
132
|
+
)
|
|
133
|
+
return _DaydreamInsight(
|
|
134
|
+
title=title or _subject_from_connection(connection),
|
|
135
|
+
connection=connection,
|
|
136
|
+
synthesis=synthesis,
|
|
137
|
+
implication=implication,
|
|
138
|
+
average=average,
|
|
139
|
+
date=date,
|
|
140
|
+
references=references,
|
|
141
|
+
path=path,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _load_markdown_insight(path: Path) -> _DaydreamInsight | None:
|
|
146
|
+
raw = path.read_text(encoding="utf-8")
|
|
147
|
+
frontmatter, body = _split_frontmatter(raw)
|
|
148
|
+
if frontmatter.get("type") != "daydream":
|
|
149
|
+
return None
|
|
150
|
+
title = _first_heading(body) or path.stem
|
|
151
|
+
average = _float_value(frontmatter.get("scores.average"))
|
|
152
|
+
if average is None:
|
|
153
|
+
average = _float_value(frontmatter.get("average"))
|
|
154
|
+
connection = _blockquote_connection(body)
|
|
155
|
+
synthesis = _section_before(body, "## Implication").strip()
|
|
156
|
+
if title:
|
|
157
|
+
synthesis = re.sub(rf"^\s*#\s+{re.escape(title)}\s*", "", synthesis).strip()
|
|
158
|
+
synthesis = re.sub(r"^>\s*Connection.*$", "", synthesis, flags=re.MULTILINE).strip()
|
|
159
|
+
implication = _section_between(body, "## Implication", "## Critic")
|
|
160
|
+
if not synthesis:
|
|
161
|
+
return None
|
|
162
|
+
date = _normalize_date(frontmatter.get("created_date") or _date_from_filename(path))
|
|
163
|
+
return _DaydreamInsight(
|
|
164
|
+
title=title,
|
|
165
|
+
connection=connection,
|
|
166
|
+
synthesis=synthesis,
|
|
167
|
+
implication=implication,
|
|
168
|
+
average=average,
|
|
169
|
+
date=date,
|
|
170
|
+
references=_references_from_frontmatter(frontmatter),
|
|
171
|
+
path=path,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _references_from_json(data: dict[str, Any], metadata: dict[str, Any]) -> list[dict[str, str]]:
|
|
176
|
+
raw_refs = metadata.get("references") or data.get("references") or []
|
|
177
|
+
references: list[dict[str, str]] = []
|
|
178
|
+
if isinstance(raw_refs, list):
|
|
179
|
+
for item in raw_refs:
|
|
180
|
+
if isinstance(item, dict):
|
|
181
|
+
locator = _text_value(item.get("path") or item.get("locator") or item.get("file"))
|
|
182
|
+
title = _text_value(item.get("title") or item.get("name"))
|
|
183
|
+
else:
|
|
184
|
+
locator = _text_value(item)
|
|
185
|
+
title = ""
|
|
186
|
+
if locator:
|
|
187
|
+
references.append({"path": locator, "title": title})
|
|
188
|
+
for side in ("a", "b"):
|
|
189
|
+
locator = _text_value(data.get(f"path_{side}"))
|
|
190
|
+
title = _text_value(data.get(f"title_{side}"))
|
|
191
|
+
if locator and not any(ref["path"] == locator for ref in references):
|
|
192
|
+
references.append({"path": locator, "title": title})
|
|
193
|
+
return references
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _references_from_frontmatter(frontmatter: dict[str, str]) -> list[dict[str, str]]:
|
|
197
|
+
references: list[dict[str, str]] = []
|
|
198
|
+
for value in frontmatter.get("source_notes", "").splitlines():
|
|
199
|
+
cleaned = _clean_wikilink(value.strip().lstrip("-").strip().strip("'\""))
|
|
200
|
+
if cleaned:
|
|
201
|
+
references.append({"path": cleaned, "title": cleaned})
|
|
202
|
+
return references
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _citations_for(insight: _DaydreamInsight) -> list[CitationInput]:
|
|
206
|
+
citations = [
|
|
207
|
+
CitationInput(source="daydream", locator=ref["path"], excerpt=ref.get("title") or None)
|
|
208
|
+
for ref in insight.references
|
|
209
|
+
if ref.get("path")
|
|
210
|
+
]
|
|
211
|
+
if citations:
|
|
212
|
+
return citations
|
|
213
|
+
return [
|
|
214
|
+
CitationInput(
|
|
215
|
+
source="daydream",
|
|
216
|
+
locator=str(insight.path),
|
|
217
|
+
excerpt=insight.connection or insight.title,
|
|
218
|
+
)
|
|
219
|
+
]
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _claim_exists(service: MemoryService, idempotency_key: str) -> bool:
|
|
223
|
+
getter = getattr(service.store, "get_claim_by_idempotency_key", None)
|
|
224
|
+
return bool(getter and getter(idempotency_key, include_citations=False))
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _idempotency_key(insight: _DaydreamInsight) -> str:
|
|
228
|
+
title = re.sub(r"\s+", " ", insight.title.strip().lower())
|
|
229
|
+
return f"daydream:{insight.date}:{title}"
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _subject_from_connection(connection: str) -> str:
|
|
233
|
+
words = re.findall(r"[A-Za-z0-9_]+", connection)
|
|
234
|
+
return " ".join(words[:3]) if words else "daydream insight"
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _dict_value(value: Any) -> dict[str, Any]:
|
|
238
|
+
return value if isinstance(value, dict) else {}
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _text_value(value: Any) -> str:
|
|
242
|
+
return str(value).strip() if value is not None else ""
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _float_value(value: Any) -> float | None:
|
|
246
|
+
try:
|
|
247
|
+
return float(value)
|
|
248
|
+
except (TypeError, ValueError):
|
|
249
|
+
return None
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def _normalize_date(value: Any) -> str:
|
|
253
|
+
text = _clean_wikilink(_text_value(value))
|
|
254
|
+
match = re.search(r"(\d{4})-?(\d{2})-?(\d{2})", text)
|
|
255
|
+
if match:
|
|
256
|
+
return f"{match.group(1)}-{match.group(2)}-{match.group(3)}"
|
|
257
|
+
return "unknown-date"
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def _date_from_filename(path: Path) -> str:
|
|
261
|
+
return _normalize_date(path.stem)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _clean_wikilink(value: str) -> str:
|
|
265
|
+
value = value.strip()
|
|
266
|
+
match = re.fullmatch(r"\[\[([^|\]]+)(?:\|[^\]]+)?\]\]", value)
|
|
267
|
+
return match.group(1).strip() if match else value
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _split_frontmatter(raw: str) -> tuple[dict[str, str], str]:
|
|
271
|
+
if not raw.startswith("---"):
|
|
272
|
+
return {}, raw
|
|
273
|
+
parts = raw.split("---", 2)
|
|
274
|
+
if len(parts) < 3:
|
|
275
|
+
return {}, raw
|
|
276
|
+
return _parse_frontmatter(parts[1]), parts[2]
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def _parse_frontmatter(raw: str) -> dict[str, str]:
|
|
280
|
+
data: dict[str, str] = {}
|
|
281
|
+
current_list: str | None = None
|
|
282
|
+
current_map: str | None = None
|
|
283
|
+
for line in raw.splitlines():
|
|
284
|
+
if not line.strip():
|
|
285
|
+
continue
|
|
286
|
+
if line.startswith(" -") and current_list:
|
|
287
|
+
existing = data.get(current_list, "")
|
|
288
|
+
data[current_list] = f"{existing}\n{line.strip()}".strip()
|
|
289
|
+
continue
|
|
290
|
+
if line.startswith(" ") and current_map and ":" in line:
|
|
291
|
+
key, value = line.strip().split(":", 1)
|
|
292
|
+
data[f"{current_map}.{key.strip()}"] = value.strip().strip("'\"")
|
|
293
|
+
continue
|
|
294
|
+
current_map = None
|
|
295
|
+
current_list = None
|
|
296
|
+
if ":" not in line:
|
|
297
|
+
continue
|
|
298
|
+
key, value = line.split(":", 1)
|
|
299
|
+
key = key.strip()
|
|
300
|
+
value = value.strip().strip("'\"")
|
|
301
|
+
data[key] = value
|
|
302
|
+
if not value:
|
|
303
|
+
current_list = key
|
|
304
|
+
current_map = key
|
|
305
|
+
return data
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def _first_heading(body: str) -> str:
|
|
309
|
+
match = re.search(r"^#\s+(.+)$", body, flags=re.MULTILINE)
|
|
310
|
+
return match.group(1).strip() if match else ""
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def _blockquote_connection(body: str) -> str:
|
|
314
|
+
match = re.search(r"^>\s*(.+)$", body, flags=re.MULTILINE)
|
|
315
|
+
return match.group(1).strip() if match else ""
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def _section_before(body: str, heading: str) -> str:
|
|
319
|
+
index = body.find(heading)
|
|
320
|
+
return body if index < 0 else body[:index]
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def _section_between(body: str, start: str, end_prefix: str) -> str:
|
|
324
|
+
start_index = body.find(start)
|
|
325
|
+
if start_index < 0:
|
|
326
|
+
return ""
|
|
327
|
+
content_start = start_index + len(start)
|
|
328
|
+
end_match = re.search(rf"^{re.escape(end_prefix)}.*$", body[content_start:], flags=re.MULTILINE)
|
|
329
|
+
if not end_match:
|
|
330
|
+
return body[content_start:].strip()
|
|
331
|
+
return body[content_start:content_start + end_match.start()].strip()
|
|
@@ -8,6 +8,7 @@ from typing import Callable, Mapping
|
|
|
8
8
|
|
|
9
9
|
from memorymaster.config import get_config
|
|
10
10
|
from memorymaster.models import Claim
|
|
11
|
+
from memorymaster.recall_fusion import RRF_K_DEFAULT, rrf_fuse
|
|
11
12
|
|
|
12
13
|
RETRIEVAL_MODES = ("legacy", "hybrid")
|
|
13
14
|
|
|
@@ -136,12 +137,12 @@ def rank_claims(
|
|
|
136
137
|
def _compute_claim_score(claim: Claim, lexical: float, confidence: float, freshness: float, vector: float, vector_enabled: bool, semantic_vectors: bool) -> float:
|
|
137
138
|
"""Compute relevance score for a claim."""
|
|
138
139
|
cfg = get_config()
|
|
140
|
+
w_l, w_c, w_f, w_v = cfg.retrieval_weights
|
|
139
141
|
if vector_enabled and semantic_vectors:
|
|
140
|
-
# Real semantic embeddings
|
|
141
|
-
|
|
142
|
+
# Real semantic embeddings use the same configurable blend as other
|
|
143
|
+
# vector-enabled ranking so env sweeps affect both paths.
|
|
144
|
+
score = (w_l * lexical) + (w_c * confidence) + (w_f * freshness) + (w_v * vector)
|
|
142
145
|
elif vector_enabled:
|
|
143
|
-
# Hash-based vectors: limited semantic value, keep lexical dominant
|
|
144
|
-
w_l, w_c, w_f, w_v = cfg.retrieval_weights
|
|
145
146
|
score = (w_l * lexical) + (w_c * confidence) + (w_f * freshness) + (w_v * vector)
|
|
146
147
|
else:
|
|
147
148
|
w_l, w_c, w_f = cfg.retrieval_weights_no_vector
|
|
@@ -180,6 +181,69 @@ def apply_session_diversity_cap(ranked: list[RankedClaim], cap: int) -> list[Ran
|
|
|
180
181
|
return result
|
|
181
182
|
|
|
182
183
|
|
|
184
|
+
def _component_rankings(rows: list[RankedClaim]) -> dict[str, list[int]]:
|
|
185
|
+
original_positions = {row.claim.id: index for index, row in enumerate(rows)}
|
|
186
|
+
|
|
187
|
+
def ranked_ids(score_attr: str) -> list[int]:
|
|
188
|
+
ordered = sorted(
|
|
189
|
+
rows,
|
|
190
|
+
key=lambda row: (
|
|
191
|
+
-float(getattr(row, score_attr)),
|
|
192
|
+
original_positions[row.claim.id],
|
|
193
|
+
),
|
|
194
|
+
)
|
|
195
|
+
return [row.claim.id for row in ordered]
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
"lexical": ranked_ids("lexical_score"),
|
|
199
|
+
"vector": ranked_ids("vector_score"),
|
|
200
|
+
"confidence": ranked_ids("confidence_score"),
|
|
201
|
+
"freshness": ranked_ids("freshness_score"),
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def apply_rrf_tiebreaker(
|
|
206
|
+
ranked: list[RankedClaim],
|
|
207
|
+
*,
|
|
208
|
+
threshold: float = 0.01,
|
|
209
|
+
k: int = RRF_K_DEFAULT,
|
|
210
|
+
enabled: bool = True,
|
|
211
|
+
) -> list[RankedClaim]:
|
|
212
|
+
if not enabled or len(ranked) < 2:
|
|
213
|
+
return ranked
|
|
214
|
+
|
|
215
|
+
threshold = max(0.0, threshold)
|
|
216
|
+
threshold_epsilon = 1e-12
|
|
217
|
+
head_count = min(10, len(ranked))
|
|
218
|
+
result = list(ranked)
|
|
219
|
+
index = 0
|
|
220
|
+
|
|
221
|
+
while index < head_count:
|
|
222
|
+
group_end = index + 1
|
|
223
|
+
while (
|
|
224
|
+
group_end < head_count
|
|
225
|
+
and abs(ranked[group_end - 1].score - ranked[group_end].score)
|
|
226
|
+
<= threshold + threshold_epsilon
|
|
227
|
+
):
|
|
228
|
+
group_end += 1
|
|
229
|
+
|
|
230
|
+
if group_end - index > 1:
|
|
231
|
+
group = ranked[index:group_end]
|
|
232
|
+
original_positions = {row.claim.id: offset for offset, row in enumerate(group)}
|
|
233
|
+
rrf_scores = rrf_fuse(_component_rankings(group), k=k)
|
|
234
|
+
result[index:group_end] = sorted(
|
|
235
|
+
group,
|
|
236
|
+
key=lambda row: (
|
|
237
|
+
-rrf_scores.get(row.claim.id, 0.0),
|
|
238
|
+
original_positions[row.claim.id],
|
|
239
|
+
),
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
index = group_end
|
|
243
|
+
|
|
244
|
+
return result
|
|
245
|
+
|
|
246
|
+
|
|
183
247
|
def rank_claim_rows(
|
|
184
248
|
query_text: str,
|
|
185
249
|
claims: list[Claim],
|
|
@@ -262,5 +326,11 @@ def rank_claim_rows(
|
|
|
262
326
|
),
|
|
263
327
|
reverse=True,
|
|
264
328
|
)
|
|
329
|
+
cfg = get_config()
|
|
330
|
+
ranked = apply_rrf_tiebreaker(
|
|
331
|
+
ranked,
|
|
332
|
+
threshold=cfg.rrf_tiebreaker_threshold,
|
|
333
|
+
enabled=cfg.rrf_tiebreaker_enabled,
|
|
334
|
+
)
|
|
265
335
|
ranked = apply_session_diversity_cap(ranked, get_config().session_diversity_cap)
|
|
266
336
|
return ranked[:limit]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memorymaster
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.17.0
|
|
4
4
|
Summary: Production-grade memory reliability system for AI coding agents. Lifecycle-managed claims with citations, conflict detection, steward governance, and MCP integration.
|
|
5
5
|
Author: wolverin0
|
|
6
6
|
License: MIT
|
|
@@ -127,6 +127,7 @@ memorymaster/jobs/__init__.py
|
|
|
127
127
|
memorymaster/jobs/calibration.py
|
|
128
128
|
memorymaster/jobs/compact_summaries.py
|
|
129
129
|
memorymaster/jobs/compactor.py
|
|
130
|
+
memorymaster/jobs/daydream_ingest.py
|
|
130
131
|
memorymaster/jobs/decay.py
|
|
131
132
|
memorymaster/jobs/dedup.py
|
|
132
133
|
memorymaster/jobs/deterministic.py
|
|
@@ -236,6 +237,7 @@ tests/test_dashboard_coverage.py
|
|
|
236
237
|
tests/test_dashboard_latency.py
|
|
237
238
|
tests/test_dashboard_lineage.py
|
|
238
239
|
tests/test_dashboard_review_queue.py
|
|
240
|
+
tests/test_daydream_ingest.py
|
|
239
241
|
tests/test_db_merge_confidence_conflict.py
|
|
240
242
|
tests/test_db_merge_coverage_v2.py
|
|
241
243
|
tests/test_decay_coverage.py
|
|
@@ -306,6 +308,8 @@ tests/test_recall_vector_fallback.py
|
|
|
306
308
|
tests/test_reliability_hardening.py
|
|
307
309
|
tests/test_resolvers_concurrent_supersede.py
|
|
308
310
|
tests/test_retrieval_profile.py
|
|
311
|
+
tests/test_retrieval_rrf_tiebreaker.py
|
|
312
|
+
tests/test_retrieval_weights.py
|
|
309
313
|
tests/test_review.py
|
|
310
314
|
tests/test_rl_trainer.py
|
|
311
315
|
tests/test_rrf_auto_gate.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "memorymaster"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.17.0"
|
|
8
8
|
description = "Production-grade memory reliability system for AI coding agents. Lifecycle-managed claims with citations, conflict detection, steward governance, and MCP integration."
|
|
9
9
|
license = {text = "MIT"}
|
|
10
10
|
authors = [{name = "wolverin0"}]
|
|
@@ -22,7 +22,7 @@ def _reset():
|
|
|
22
22
|
class TestConfigDefaults:
|
|
23
23
|
def test_default_retrieval_weights(self):
|
|
24
24
|
cfg = Config()
|
|
25
|
-
assert cfg.retrieval_weights == (0.
|
|
25
|
+
assert cfg.retrieval_weights == (0.30, 0.20, 0.10, 0.40)
|
|
26
26
|
|
|
27
27
|
def test_default_no_vector_weights(self):
|
|
28
28
|
cfg = Config()
|
|
@@ -58,6 +58,12 @@ class TestConfigEnvOverrides:
|
|
|
58
58
|
cfg = load_config()
|
|
59
59
|
assert cfg.retrieval_weights == (0.40, 0.25, 0.20, 0.15)
|
|
60
60
|
|
|
61
|
+
def test_individual_retrieval_weight_env(self, monkeypatch):
|
|
62
|
+
monkeypatch.setenv("MEMORYMASTER_RETRIEVAL_WEIGHTS", "0.40,0.25,0.20,0.15")
|
|
63
|
+
monkeypatch.setenv("MEMORYMASTER_W_LEX", "0.55")
|
|
64
|
+
cfg = load_config()
|
|
65
|
+
assert cfg.retrieval_weights == (0.55, 0.25, 0.20, 0.15)
|
|
66
|
+
|
|
61
67
|
def test_retrieval_weights_no_vector_env(self, monkeypatch):
|
|
62
68
|
monkeypatch.setenv("MEMORYMASTER_RETRIEVAL_WEIGHTS_NO_VECTOR", "0.60,0.25,0.15")
|
|
63
69
|
cfg = load_config()
|