brainlayer 1.5.2__tar.gz → 1.5.3__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.
- {brainlayer-1.5.2 → brainlayer-1.5.3}/PKG-INFO +3 -2
- {brainlayer-1.5.2 → brainlayer-1.5.3}/pyproject.toml +3 -2
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/hotlane_brainbar_daemon.py +310 -33
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/backup-daily.sh +5 -1
- brainlayer-1.5.3/scripts/launchd/com.brainlayer.t3-ingest.plist +53 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.wal-checkpoint.plist +1 -2
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/install.sh +7 -2
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/throughput-watchdog.py +225 -39
- {brainlayer-1.5.2 → brainlayer-1.5.3}/server.json +2 -2
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/__init__.py +1 -1
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/agent_provenance.py +13 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/backup_daily.py +286 -54
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/brainbar_hybrid_helper.py +1 -1
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/cli/__init__.py +85 -11
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/deploy_drift.py +81 -24
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/doctor.py +37 -8
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/drain.py +161 -51
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/health_check.py +40 -21
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/index_new.py +31 -25
- brainlayer-1.5.3/src/brainlayer/ingest/__init__.py +27 -0
- brainlayer-1.5.3/src/brainlayer/ingest/t3.py +404 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/launchd_primitive.py +31 -6
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/maintenance.py +108 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/mcp/__init__.py +153 -62
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/mcp/_shared.py +1 -1
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/mcp/palette.py +1 -1
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/mcp/store_handler.py +9 -0
- brainlayer-1.5.3/src/brainlayer/paths.py +55 -0
- brainlayer-1.5.3/src/brainlayer/pause.py +46 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/queue_io.py +6 -2
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/runtime_store.py +2 -0
- brainlayer-1.5.3/src/brainlayer/setup.py +278 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/store.py +14 -0
- brainlayer-1.5.3/src/brainlayer/t3_provenance.py +97 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/vector_store.py +46 -12
- brainlayer-1.5.3/src/brainlayer/wal_checkpoint.py +175 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/watcher.py +504 -127
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/watcher_bridge.py +127 -14
- brainlayer-1.5.2/src/brainlayer/ingest/__init__.py +0 -1
- brainlayer-1.5.2/src/brainlayer/paths.py +0 -28
- brainlayer-1.5.2/src/brainlayer/setup.py +0 -114
- brainlayer-1.5.2/src/brainlayer/wal_checkpoint.py +0 -72
- {brainlayer-1.5.2 → brainlayer-1.5.3}/.gitignore +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/LICENSE +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/README.md +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/brainlayer-env-run.sh +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/brainlayer.env.example +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.backup-daily.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.decay.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.drain.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.enrichment.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.health-check.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.hotlane-brainbar.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.index.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.jsonl-backup.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.maintenance-nightly.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.maintenance-weekly.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.p0-counter.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.repair-fts.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.throughput-watchdog.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.tier0-watchdog.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/com.brainlayer.watch.plist +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/launchd/jsonl-backup.sh +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/scripts/tier0-watchdog.sh +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/_helpers.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/agent_profiles.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/alarm.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/bitemporal.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/calibrate.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/chunk_origin.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/chunk_origin_backfill.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/classify.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/claude_paths.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/cli/wizard.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/cli_new.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/cloud_backfill.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/clustering.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/config.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/content_class.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/correction_judge.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/data/agents_registry.yaml +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/data/sandbox_seeds/skill-eval-baseline.json +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/db_shrink.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/decay.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/decay_backfill.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/decay_job.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/dedupe.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/drain_liveness.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/embeddings.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/engine.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/enrichment_controller.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/__init__.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/abcde_enrich_runner.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/abcde_variants.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/abcde_variants.yaml +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/benchmark.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/enrichment_gold.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/enrichment_graders.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/enrichment_judge.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/enrichment_llm_judge.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/enrichment_quality_benchmark.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/experiment_store.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/fixtures/README.md +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/labeling/enrichment-labeler.html +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/phoenix_gate/__init__.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/phoenix_gate/__main__.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/phoenix_gate/baseline_store.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/phoenix_gate/cli.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/phoenix_gate/models.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/phoenix_gate/phoenix_client.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/phoenix_gate/regression_gate.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/eval/phoenix_gate/triggers.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/fallback_replay.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/git_learning.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/hooks/__init__.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/hooks/indexer.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/ingest/codex.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/ingest_denylist.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/ingest_guard.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/isolation_proof.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/jsonl_backup.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/kg/__init__.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/kg_cleanup.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/kg_judge.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/kg_promotion.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/kg_repo.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/kg_review_session.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/kg_session_finish.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/kg_session_harvest.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/lexical_defense.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/lexical_defense_dictionary.json +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/mcp/_format.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/mcp/enrich_handler.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/mcp/entity_handler.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/mcp/search_handler.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/mcp/tags_handler.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/mcp_stdio_bridge.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/memory_types.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/migrate.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/p0_longitudinal_count.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/parent_death.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/phonetic.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/__init__.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/agent_enrichment.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/analyze_communication.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/batch_extraction.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/brain_graph.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/chat_tags.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/chunk.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/classify.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/cluster_sampling.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/code_intelligence.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/correction_detection.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/correction_mining.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/digest.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/enrichment.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/enrichment_tiers.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/entity_extraction.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/entity_resolution.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/extract.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/extract_claude_desktop.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/extract_corrections.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/extract_markdown.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/extract_whatsapp.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/frustration_mining.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/git_overlay.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/kg_extraction.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/kg_extraction_groq.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/longitudinal_analyzer.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/obsidian_export.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/operation_grouping.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/plan_linking.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/rate_limiter.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/sanitize.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/secret_scrub.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/semantic_style.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/sentiment.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/session_enrichment.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/style_embed.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/style_index.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/tag_entity_promotion.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/temporal_chains.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/time_batcher.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/unified_timeline.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/pipeline/write_queue.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/provenance.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/provenance_autosupersede.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/provenance_integration.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/queue_merge.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/reembed_backfill.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/sandbox_db.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/scoping.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/search_fanout.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/search_profile.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/search_repo.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/session_repo.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/storage.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/system_prompt_guard.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/tag_normalization.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/taxonomy.json +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/telemetry.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/types.py +0 -0
- {brainlayer-1.5.2 → brainlayer-1.5.3}/src/brainlayer/writer_telemetry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: brainlayer
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.3
|
|
4
4
|
Summary: Persistent memory MCP server for AI agents — 13 tools, semantic search, knowledge graph, on-device SQLite
|
|
5
5
|
Project-URL: Homepage, https://brainlayer.etanheyman.com
|
|
6
6
|
Project-URL: Repository, https://github.com/EtanHey/brainlayer
|
|
@@ -23,7 +23,8 @@ Requires-Dist: abydos>=0.5.0
|
|
|
23
23
|
Requires-Dist: apsw>=3.45.0
|
|
24
24
|
Requires-Dist: google-api-python-client>=2.0.0
|
|
25
25
|
Requires-Dist: google-auth>=2.0.0
|
|
26
|
-
Requires-Dist:
|
|
26
|
+
Requires-Dist: jsonschema>=4.20.0
|
|
27
|
+
Requires-Dist: mcp<3.0.0,>=2.0.0
|
|
27
28
|
Requires-Dist: numpy<3.0,>=1.22
|
|
28
29
|
Requires-Dist: orjson>=3.9.0
|
|
29
30
|
Requires-Dist: pydantic>=2.0.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "brainlayer"
|
|
3
|
-
version = "1.5.
|
|
3
|
+
version = "1.5.3"
|
|
4
4
|
description = "Persistent memory MCP server for AI agents — 13 tools, semantic search, knowledge graph, on-device SQLite"
|
|
5
5
|
license = {text = "Apache-2.0"}
|
|
6
6
|
readme = "README.md"
|
|
@@ -16,7 +16,8 @@ dependencies = [
|
|
|
16
16
|
"sentence-transformers>=2.2.0",
|
|
17
17
|
|
|
18
18
|
# MCP server
|
|
19
|
-
"mcp>=
|
|
19
|
+
"mcp>=2.0.0,<3.0.0",
|
|
20
|
+
"jsonschema>=4.20.0", # MCP v2 low-level handlers require explicit schema validation
|
|
20
21
|
|
|
21
22
|
# CLI
|
|
22
23
|
"typer>=0.9.0",
|
|
@@ -15,6 +15,7 @@ import logging
|
|
|
15
15
|
import os
|
|
16
16
|
import signal
|
|
17
17
|
import time
|
|
18
|
+
from collections import OrderedDict
|
|
18
19
|
from pathlib import Path
|
|
19
20
|
from typing import Callable, NamedTuple
|
|
20
21
|
|
|
@@ -41,8 +42,88 @@ MAX_BACKLOG_BATCH = 16
|
|
|
41
42
|
DEFAULT_HOTLANE_WRITE_BUSY_TIMEOUT_MS = 1000
|
|
42
43
|
MAX_APSW_BUSY_TIMEOUT_MS = 2_147_483_647
|
|
43
44
|
VECTOR_WRITE_YIELD_SECONDS = 0.005
|
|
45
|
+
HOT_CANDIDATE_SCAN_LIMIT = 256
|
|
46
|
+
HOT_CANDIDATE_HEAD_LIMIT = HOT_CANDIDATE_SCAN_LIMIT // 2
|
|
47
|
+
MAX_HOT_CANDIDATE_RETRIES = 256
|
|
44
48
|
_sleep = time.sleep
|
|
45
49
|
|
|
50
|
+
HOT_CANDIDATE_SCAN_SQL = """
|
|
51
|
+
SELECT
|
|
52
|
+
c.id,
|
|
53
|
+
c.content,
|
|
54
|
+
c.source_file,
|
|
55
|
+
c.source,
|
|
56
|
+
c.archived_at,
|
|
57
|
+
c.superseded_by,
|
|
58
|
+
c.aggregated_into,
|
|
59
|
+
COALESCE(c.archived, 0),
|
|
60
|
+
COALESCE(c.status, 'active'),
|
|
61
|
+
r.id
|
|
62
|
+
FROM chunks c
|
|
63
|
+
LEFT JOIN chunk_vectors_rowids r ON r.id = c.id
|
|
64
|
+
ORDER BY c.created_at DESC
|
|
65
|
+
LIMIT ?
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
HOT_CANDIDATE_ROWID_SCAN_SQL = """
|
|
69
|
+
SELECT
|
|
70
|
+
c.rowid,
|
|
71
|
+
c.id,
|
|
72
|
+
c.content,
|
|
73
|
+
c.source_file,
|
|
74
|
+
c.source,
|
|
75
|
+
c.archived_at,
|
|
76
|
+
c.superseded_by,
|
|
77
|
+
c.aggregated_into,
|
|
78
|
+
COALESCE(c.archived, 0),
|
|
79
|
+
COALESCE(c.status, 'active'),
|
|
80
|
+
r.id
|
|
81
|
+
FROM chunks c
|
|
82
|
+
LEFT JOIN chunk_vectors_rowids r ON r.id = c.id
|
|
83
|
+
ORDER BY c.rowid DESC
|
|
84
|
+
LIMIT ?
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
HOT_CANDIDATE_ROWID_PAGE_SQL = """
|
|
88
|
+
SELECT
|
|
89
|
+
c.rowid,
|
|
90
|
+
c.id,
|
|
91
|
+
c.content,
|
|
92
|
+
c.source_file,
|
|
93
|
+
c.source,
|
|
94
|
+
c.archived_at,
|
|
95
|
+
c.superseded_by,
|
|
96
|
+
c.aggregated_into,
|
|
97
|
+
COALESCE(c.archived, 0),
|
|
98
|
+
COALESCE(c.status, 'active'),
|
|
99
|
+
r.id
|
|
100
|
+
FROM chunks c
|
|
101
|
+
LEFT JOIN chunk_vectors_rowids r ON r.id = c.id
|
|
102
|
+
WHERE c.rowid < ?
|
|
103
|
+
ORDER BY c.rowid DESC
|
|
104
|
+
LIMIT ?
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
HOT_CANDIDATE_ROWID_FORWARD_SQL = """
|
|
108
|
+
SELECT
|
|
109
|
+
c.rowid,
|
|
110
|
+
c.id,
|
|
111
|
+
c.content,
|
|
112
|
+
c.source_file,
|
|
113
|
+
c.source,
|
|
114
|
+
c.archived_at,
|
|
115
|
+
c.superseded_by,
|
|
116
|
+
c.aggregated_into,
|
|
117
|
+
COALESCE(c.archived, 0),
|
|
118
|
+
COALESCE(c.status, 'active'),
|
|
119
|
+
r.id
|
|
120
|
+
FROM chunks c
|
|
121
|
+
LEFT JOIN chunk_vectors_rowids r ON r.id = c.id
|
|
122
|
+
WHERE c.rowid > ?
|
|
123
|
+
ORDER BY c.rowid ASC
|
|
124
|
+
LIMIT ?
|
|
125
|
+
"""
|
|
126
|
+
|
|
46
127
|
|
|
47
128
|
class CycleResult(NamedTuple):
|
|
48
129
|
embedded: int = 0
|
|
@@ -64,6 +145,183 @@ class EmbeddedVector(NamedTuple):
|
|
|
64
145
|
embedding: list[float]
|
|
65
146
|
|
|
66
147
|
|
|
148
|
+
def _candidates_from_scanned_rows(
|
|
149
|
+
rows: list[tuple], *, limit: int, exclude_ids: set[str] | None = None
|
|
150
|
+
) -> tuple[list[EmbedCandidate], int | None, int | None, bool]:
|
|
151
|
+
if limit <= 0:
|
|
152
|
+
return [], None, None, False
|
|
153
|
+
candidates: list[EmbedCandidate] = []
|
|
154
|
+
exclude_ids = exclude_ids or set()
|
|
155
|
+
first_candidate_rowid: int | None = None
|
|
156
|
+
last_inspected_rowid: int | None = None
|
|
157
|
+
for index, row in enumerate(rows):
|
|
158
|
+
(
|
|
159
|
+
rowid,
|
|
160
|
+
chunk_id,
|
|
161
|
+
content,
|
|
162
|
+
source_file,
|
|
163
|
+
source,
|
|
164
|
+
archived_at,
|
|
165
|
+
superseded_by,
|
|
166
|
+
aggregated_into,
|
|
167
|
+
archived,
|
|
168
|
+
status,
|
|
169
|
+
vector_id,
|
|
170
|
+
) = row
|
|
171
|
+
last_inspected_rowid = int(rowid)
|
|
172
|
+
eligible = (
|
|
173
|
+
vector_id is None
|
|
174
|
+
and source_file == "brainbar-store"
|
|
175
|
+
and source == "mcp"
|
|
176
|
+
and content
|
|
177
|
+
and archived_at is None
|
|
178
|
+
and superseded_by is None
|
|
179
|
+
and aggregated_into is None
|
|
180
|
+
and not archived
|
|
181
|
+
and status == "active"
|
|
182
|
+
)
|
|
183
|
+
if eligible:
|
|
184
|
+
if first_candidate_rowid is None:
|
|
185
|
+
first_candidate_rowid = int(rowid)
|
|
186
|
+
if str(chunk_id) in exclude_ids:
|
|
187
|
+
continue
|
|
188
|
+
candidates.append(EmbedCandidate(str(chunk_id), str(content)))
|
|
189
|
+
if len(candidates) >= limit:
|
|
190
|
+
return candidates, first_candidate_rowid, last_inspected_rowid, index == len(rows) - 1
|
|
191
|
+
return candidates, first_candidate_rowid, last_inspected_rowid, True
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class HotCandidateScanner:
|
|
195
|
+
"""Scan bounded rowid lanes while retaining returned candidates for retry."""
|
|
196
|
+
|
|
197
|
+
def __init__(self) -> None:
|
|
198
|
+
self._before_rowid: int | None = None
|
|
199
|
+
self._newest_seen_rowid: int | None = None
|
|
200
|
+
self._retries: OrderedDict[str, EmbedCandidate] = OrderedDict()
|
|
201
|
+
self._retry_turn = True
|
|
202
|
+
self._retry_buffer_full_logged = False
|
|
203
|
+
|
|
204
|
+
def _refresh_retries(self, cursor: apsw.Cursor) -> None:
|
|
205
|
+
if not self._retries:
|
|
206
|
+
return
|
|
207
|
+
placeholders = ",".join("?" for _ in self._retries)
|
|
208
|
+
rows = cursor.execute(
|
|
209
|
+
f"""
|
|
210
|
+
SELECT c.id, c.content
|
|
211
|
+
FROM chunks c
|
|
212
|
+
LEFT JOIN chunk_vectors_rowids r ON r.id = c.id
|
|
213
|
+
WHERE c.id IN ({placeholders})
|
|
214
|
+
AND r.id IS NULL
|
|
215
|
+
AND c.source_file = 'brainbar-store'
|
|
216
|
+
AND c.source = 'mcp'
|
|
217
|
+
AND c.content IS NOT NULL
|
|
218
|
+
AND c.content != ''
|
|
219
|
+
AND c.archived_at IS NULL
|
|
220
|
+
AND c.superseded_by IS NULL
|
|
221
|
+
AND c.aggregated_into IS NULL
|
|
222
|
+
AND COALESCE(c.archived, 0) = 0
|
|
223
|
+
AND COALESCE(c.status, 'active') = 'active'
|
|
224
|
+
""",
|
|
225
|
+
tuple(self._retries),
|
|
226
|
+
)
|
|
227
|
+
active = {str(chunk_id): EmbedCandidate(str(chunk_id), str(content)) for chunk_id, content in rows}
|
|
228
|
+
for chunk_id in list(self._retries):
|
|
229
|
+
if chunk_id not in active:
|
|
230
|
+
del self._retries[chunk_id]
|
|
231
|
+
else:
|
|
232
|
+
self._retries[chunk_id] = active[chunk_id]
|
|
233
|
+
if len(self._retries) < MAX_HOT_CANDIDATE_RETRIES:
|
|
234
|
+
self._retry_buffer_full_logged = False
|
|
235
|
+
|
|
236
|
+
def _take_retries(self, *, limit: int) -> list[EmbedCandidate]:
|
|
237
|
+
selected: list[EmbedCandidate] = []
|
|
238
|
+
for _ in range(min(limit, len(self._retries))):
|
|
239
|
+
chunk_id, candidate = self._retries.popitem(last=False)
|
|
240
|
+
self._retries[chunk_id] = candidate
|
|
241
|
+
selected.append(candidate)
|
|
242
|
+
return selected
|
|
243
|
+
|
|
244
|
+
def _retain(self, candidates: list[EmbedCandidate]) -> None:
|
|
245
|
+
for candidate in candidates:
|
|
246
|
+
if candidate.chunk_id in self._retries:
|
|
247
|
+
continue
|
|
248
|
+
if len(self._retries) >= MAX_HOT_CANDIDATE_RETRIES:
|
|
249
|
+
if not self._retry_buffer_full_logged:
|
|
250
|
+
LOGGER.warning("hot candidate retry buffer full; pausing new retry retention")
|
|
251
|
+
self._retry_buffer_full_logged = True
|
|
252
|
+
break
|
|
253
|
+
self._retries[candidate.chunk_id] = candidate
|
|
254
|
+
|
|
255
|
+
def __call__(self, store: VectorStore, *, limit: int) -> list[EmbedCandidate]:
|
|
256
|
+
cursor = store.conn.cursor()
|
|
257
|
+
self._refresh_retries(cursor)
|
|
258
|
+
if limit <= 0:
|
|
259
|
+
return []
|
|
260
|
+
if limit == 1 and self._retries:
|
|
261
|
+
retry_limit = 1 if self._retry_turn else 0
|
|
262
|
+
self._retry_turn = not self._retry_turn
|
|
263
|
+
else:
|
|
264
|
+
retry_limit = min(len(self._retries), max(1, limit // 2))
|
|
265
|
+
candidates = self._take_retries(limit=retry_limit)
|
|
266
|
+
retention_slots = MAX_HOT_CANDIDATE_RETRIES - len(self._retries)
|
|
267
|
+
scan_limit = min(limit - len(candidates), retention_slots)
|
|
268
|
+
if scan_limit <= 0:
|
|
269
|
+
return candidates
|
|
270
|
+
retry_ids = set(self._retries)
|
|
271
|
+
head_rows = list(cursor.execute(HOT_CANDIDATE_ROWID_SCAN_SQL, (HOT_CANDIDATE_HEAD_LIMIT,)))
|
|
272
|
+
head_candidates, _, last_inspected_rowid, _ = _candidates_from_scanned_rows(
|
|
273
|
+
head_rows,
|
|
274
|
+
limit=scan_limit,
|
|
275
|
+
exclude_ids=retry_ids,
|
|
276
|
+
)
|
|
277
|
+
candidates.extend(head_candidates)
|
|
278
|
+
retention_slots -= len(head_candidates)
|
|
279
|
+
if not head_rows:
|
|
280
|
+
self._retain(candidates)
|
|
281
|
+
return candidates
|
|
282
|
+
if self._newest_seen_rowid is None:
|
|
283
|
+
self._newest_seen_rowid = last_inspected_rowid
|
|
284
|
+
if self._before_rowid is None and last_inspected_rowid is not None:
|
|
285
|
+
self._before_rowid = last_inspected_rowid
|
|
286
|
+
if len(candidates) >= limit or retention_slots <= 0:
|
|
287
|
+
self._retain(candidates)
|
|
288
|
+
return candidates
|
|
289
|
+
|
|
290
|
+
page_limit = HOT_CANDIDATE_SCAN_LIMIT - HOT_CANDIDATE_HEAD_LIMIT
|
|
291
|
+
forward_rows = list(
|
|
292
|
+
cursor.execute(
|
|
293
|
+
HOT_CANDIDATE_ROWID_FORWARD_SQL,
|
|
294
|
+
(self._newest_seen_rowid, page_limit),
|
|
295
|
+
)
|
|
296
|
+
)
|
|
297
|
+
if forward_rows:
|
|
298
|
+
forward_candidates, _, last_inspected_rowid, _ = _candidates_from_scanned_rows(
|
|
299
|
+
forward_rows,
|
|
300
|
+
limit=min(limit - len(candidates), retention_slots),
|
|
301
|
+
exclude_ids=retry_ids | {candidate.chunk_id for candidate in candidates},
|
|
302
|
+
)
|
|
303
|
+
candidates.extend(forward_candidates)
|
|
304
|
+
retention_slots -= len(forward_candidates)
|
|
305
|
+
self._newest_seen_rowid = last_inspected_rowid
|
|
306
|
+
if len(candidates) >= limit or retention_slots <= 0 or self._before_rowid is None:
|
|
307
|
+
self._retain(candidates)
|
|
308
|
+
return candidates[:limit]
|
|
309
|
+
|
|
310
|
+
page_rows = list(cursor.execute(HOT_CANDIDATE_ROWID_PAGE_SQL, (self._before_rowid, page_limit)))
|
|
311
|
+
if page_rows:
|
|
312
|
+
page_candidates, _, last_inspected_rowid, fully_scanned = _candidates_from_scanned_rows(
|
|
313
|
+
page_rows,
|
|
314
|
+
limit=min(limit - len(candidates), retention_slots),
|
|
315
|
+
exclude_ids=retry_ids | {candidate.chunk_id for candidate in candidates},
|
|
316
|
+
)
|
|
317
|
+
candidates.extend(page_candidates)
|
|
318
|
+
self._before_rowid = last_inspected_rowid
|
|
319
|
+
if fully_scanned and len(page_rows) < page_limit:
|
|
320
|
+
self._before_rowid = None
|
|
321
|
+
self._retain(candidates)
|
|
322
|
+
return candidates[:limit]
|
|
323
|
+
|
|
324
|
+
|
|
67
325
|
def _stop(_signum: int, _frame: object) -> None:
|
|
68
326
|
global STOP
|
|
69
327
|
STOP = True
|
|
@@ -95,26 +353,38 @@ def _candidate_chunk_ids(store: VectorStore, *, limit: int) -> list[str]:
|
|
|
95
353
|
|
|
96
354
|
def _candidate_chunk_rows(store: VectorStore, *, limit: int) -> list[EmbedCandidate]:
|
|
97
355
|
rows = store.conn.cursor().execute(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
FROM chunks c
|
|
101
|
-
LEFT JOIN chunk_vectors_rowids r ON r.id = c.id
|
|
102
|
-
WHERE r.id IS NULL
|
|
103
|
-
AND c.source_file = 'brainbar-store'
|
|
104
|
-
AND c.source = 'mcp'
|
|
105
|
-
AND c.content IS NOT NULL
|
|
106
|
-
AND c.content != ''
|
|
107
|
-
AND c.archived_at IS NULL
|
|
108
|
-
AND c.superseded_by IS NULL
|
|
109
|
-
AND c.aggregated_into IS NULL
|
|
110
|
-
AND COALESCE(c.archived, 0) = 0
|
|
111
|
-
AND COALESCE(c.status, 'active') = 'active'
|
|
112
|
-
ORDER BY c.created_at DESC
|
|
113
|
-
LIMIT ?
|
|
114
|
-
""",
|
|
115
|
-
(limit,),
|
|
356
|
+
HOT_CANDIDATE_SCAN_SQL,
|
|
357
|
+
(HOT_CANDIDATE_SCAN_LIMIT,),
|
|
116
358
|
)
|
|
117
|
-
|
|
359
|
+
candidates: list[EmbedCandidate] = []
|
|
360
|
+
for row in rows:
|
|
361
|
+
(
|
|
362
|
+
chunk_id,
|
|
363
|
+
content,
|
|
364
|
+
source_file,
|
|
365
|
+
source,
|
|
366
|
+
archived_at,
|
|
367
|
+
superseded_by,
|
|
368
|
+
aggregated_into,
|
|
369
|
+
archived,
|
|
370
|
+
status,
|
|
371
|
+
vector_id,
|
|
372
|
+
) = row
|
|
373
|
+
if (
|
|
374
|
+
vector_id is None
|
|
375
|
+
and source_file == "brainbar-store"
|
|
376
|
+
and source == "mcp"
|
|
377
|
+
and content
|
|
378
|
+
and archived_at is None
|
|
379
|
+
and superseded_by is None
|
|
380
|
+
and aggregated_into is None
|
|
381
|
+
and not archived
|
|
382
|
+
and status == "active"
|
|
383
|
+
):
|
|
384
|
+
candidates.append(EmbedCandidate(str(chunk_id), str(content)))
|
|
385
|
+
if len(candidates) >= limit:
|
|
386
|
+
break
|
|
387
|
+
return candidates
|
|
118
388
|
|
|
119
389
|
|
|
120
390
|
def _pending_chunk_rows(store: VectorStore, *, limit: int) -> list[EmbedCandidate]:
|
|
@@ -419,9 +689,13 @@ def _queue_depth(queue_dir: Path) -> int:
|
|
|
419
689
|
return 0
|
|
420
690
|
|
|
421
691
|
|
|
692
|
+
def _is_enrichment_queue_file(path: Path) -> bool:
|
|
693
|
+
return path.name.startswith("enrichment-") or path.name.startswith("queue-enrichment")
|
|
694
|
+
|
|
695
|
+
|
|
422
696
|
def _high_priority_queue_depth(queue_dir: Path) -> int:
|
|
423
697
|
try:
|
|
424
|
-
return sum(1 for path in queue_dir.glob("*.jsonl") if not path
|
|
698
|
+
return sum(1 for path in queue_dir.glob("*.jsonl") if not _is_enrichment_queue_file(path))
|
|
425
699
|
except OSError:
|
|
426
700
|
return 0
|
|
427
701
|
|
|
@@ -505,6 +779,8 @@ def run(
|
|
|
505
779
|
last_backlog = time_fn() - backlog_interval
|
|
506
780
|
last_enrich = 0.0
|
|
507
781
|
enrich_disabled = False
|
|
782
|
+
queue_backpressure_active = False
|
|
783
|
+
hot_candidate_scanner = HotCandidateScanner()
|
|
508
784
|
cycles = 0
|
|
509
785
|
backlog_batch = min(max(backlog_batch, 0), MAX_BACKLOG_BATCH)
|
|
510
786
|
LOGGER.info("hotlane adapter started db=%s", db_path)
|
|
@@ -515,23 +791,23 @@ def run(
|
|
|
515
791
|
now = time_fn()
|
|
516
792
|
queue_has_backlog = queue_depth_fn(queue_dir) > 0
|
|
517
793
|
queue_has_high_priority_backlog = queue_has_backlog and high_priority_queue_depth_fn(queue_dir) > 0
|
|
518
|
-
if
|
|
519
|
-
if
|
|
794
|
+
if queue_has_high_priority_backlog:
|
|
795
|
+
if not queue_backpressure_active:
|
|
520
796
|
LOGGER.info("durable high-priority queue has backlog; yielding all hotlane writer work")
|
|
521
|
-
|
|
522
|
-
LOGGER.info("durable queue has backlog; yielding all hotlane writer work")
|
|
797
|
+
queue_backpressure_active = True
|
|
523
798
|
cycles += 1
|
|
524
799
|
sleep_fn(interval)
|
|
525
800
|
continue
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
801
|
+
queue_backpressure_active = False
|
|
802
|
+
cycle_backlog_batch = backlog_batch if backlog_batch > 0 and now - last_backlog >= backlog_interval else 0
|
|
803
|
+
cycle_enrich_limit = (
|
|
804
|
+
enrich_limit
|
|
805
|
+
if not queue_has_backlog
|
|
806
|
+
and not enrich_disabled
|
|
807
|
+
and enrich_limit > 0
|
|
808
|
+
and now - last_enrich >= enrich_interval
|
|
809
|
+
else 0
|
|
810
|
+
)
|
|
535
811
|
if cycle_backlog_batch > 0:
|
|
536
812
|
last_backlog = now
|
|
537
813
|
if cycle_enrich_limit > 0:
|
|
@@ -546,6 +822,7 @@ def run(
|
|
|
546
822
|
embed_batch_fn=embed_batch_fn,
|
|
547
823
|
enrich_limit=cycle_enrich_limit,
|
|
548
824
|
enrich_since_hours=enrich_since_hours,
|
|
825
|
+
candidate_rows_fn=hot_candidate_scanner,
|
|
549
826
|
)
|
|
550
827
|
else:
|
|
551
828
|
store = vector_store_cls(db_path)
|
|
@@ -3,8 +3,12 @@ set -euo pipefail
|
|
|
3
3
|
|
|
4
4
|
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:$HOME/.local/bin"
|
|
5
5
|
export PYTHONUNBUFFERED=1
|
|
6
|
-
: "${
|
|
6
|
+
: "${BRAINLAYER_BACKUP_CLIENT_TIMEOUT_SECONDS:=0}"
|
|
7
|
+
export BRAINLAYER_BACKUP_CLIENT_TIMEOUT_SECONDS
|
|
8
|
+
: "${BRAINLAYER_BACKUP_TIMEOUT_SECONDS:=7200}"
|
|
7
9
|
export BRAINLAYER_BACKUP_TIMEOUT_SECONDS
|
|
10
|
+
: "${BRAINLAYER_BACKUP_ATTEMPT_MAX_AGE_SECONDS:=86400}"
|
|
11
|
+
export BRAINLAYER_BACKUP_ATTEMPT_MAX_AGE_SECONDS
|
|
8
12
|
: "${BRAINLAYER_BACKUP_LOG_PROVENANCE:=real}"
|
|
9
13
|
export BRAINLAYER_BACKUP_LOG_PROVENANCE
|
|
10
14
|
BRAINLAYER_DIR="${BRAINLAYER_DIR:-__BRAINLAYER_DIR_VALUE__}"
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>Label</key>
|
|
6
|
+
<string>com.brainlayer.t3-ingest</string>
|
|
7
|
+
<key>ProgramArguments</key>
|
|
8
|
+
<array>
|
|
9
|
+
<string>__BRAINLAYER_ENV_RUN__</string>
|
|
10
|
+
<string>__BRAINLAYER_BIN__</string>
|
|
11
|
+
<string>ingest-t3</string>
|
|
12
|
+
</array>
|
|
13
|
+
<key>StartCalendarInterval</key>
|
|
14
|
+
<dict>
|
|
15
|
+
<key>Hour</key>
|
|
16
|
+
<integer>3</integer>
|
|
17
|
+
<key>Minute</key>
|
|
18
|
+
<integer>45</integer>
|
|
19
|
+
</dict>
|
|
20
|
+
<key>RunAtLoad</key>
|
|
21
|
+
<true/>
|
|
22
|
+
<key>StandardOutPath</key>
|
|
23
|
+
<string>__HOME__/Library/Logs/brainlayer/t3-ingest.out.log</string>
|
|
24
|
+
<key>StandardErrorPath</key>
|
|
25
|
+
<string>__HOME__/Library/Logs/brainlayer/t3-ingest.err.log</string>
|
|
26
|
+
<key>EnvironmentVariables</key>
|
|
27
|
+
<dict>
|
|
28
|
+
<key>PATH</key>
|
|
29
|
+
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:__HOME__/.local/bin</string>
|
|
30
|
+
<key>PYTHONUNBUFFERED</key>
|
|
31
|
+
<string>1</string>
|
|
32
|
+
<key>BRAINLAYER_REPO_ROOT</key>
|
|
33
|
+
<string>__BRAINLAYER_DIR__</string>
|
|
34
|
+
<key>BRAINLAYER_ENV_FILE</key>
|
|
35
|
+
<string>__BRAINLAYER_ENV_FILE__</string>
|
|
36
|
+
<key>BRAINLAYER_LAUNCHD_SERVICE</key>
|
|
37
|
+
<string>t3-ingest</string>
|
|
38
|
+
</dict>
|
|
39
|
+
<key>Nice</key>
|
|
40
|
+
<integer>10</integer>
|
|
41
|
+
<key>ProcessType</key>
|
|
42
|
+
<string>Background</string>
|
|
43
|
+
<key>ExitTimeOut</key>
|
|
44
|
+
<integer>1800</integer>
|
|
45
|
+
<key>LowPriorityIO</key>
|
|
46
|
+
<true/>
|
|
47
|
+
<key>SoftResourceLimits</key>
|
|
48
|
+
<dict>
|
|
49
|
+
<key>NumberOfFiles</key>
|
|
50
|
+
<integer>4096</integer>
|
|
51
|
+
</dict>
|
|
52
|
+
</dict>
|
|
53
|
+
</plist>
|
|
@@ -11,11 +11,10 @@
|
|
|
11
11
|
<string>wal-checkpoint</string>
|
|
12
12
|
<string>--mode</string>
|
|
13
13
|
<string>TRUNCATE</string>
|
|
14
|
+
<string>--retry-busy</string>
|
|
14
15
|
</array>
|
|
15
16
|
<key>StartCalendarInterval</key>
|
|
16
17
|
<dict>
|
|
17
|
-
<key>Weekday</key>
|
|
18
|
-
<integer>0</integer>
|
|
19
18
|
<key>Hour</key>
|
|
20
19
|
<integer>4</integer>
|
|
21
20
|
<key>Minute</key>
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
# ./scripts/launchd/install.sh throughput-watchdog # Install watcher throughput watchdog only
|
|
21
21
|
# ./scripts/launchd/install.sh hotlane # Install BrainBar hotlane embed/enrich daemon only
|
|
22
22
|
# ./scripts/launchd/install.sh p0-counter # Install daily P0 longitudinal counter only
|
|
23
|
+
# ./scripts/launchd/install.sh t3-ingest # Install T3 thread ingestion only
|
|
23
24
|
# ./scripts/launchd/install.sh remove # Unload and remove all
|
|
24
25
|
set -euo pipefail
|
|
25
26
|
|
|
@@ -661,13 +662,16 @@ case "${1:-all}" in
|
|
|
661
662
|
p0-counter)
|
|
662
663
|
install_plist p0-counter
|
|
663
664
|
;;
|
|
665
|
+
t3-ingest)
|
|
666
|
+
install_plist t3-ingest
|
|
667
|
+
;;
|
|
664
668
|
all)
|
|
665
669
|
install_env_runner
|
|
666
670
|
verify_config_file
|
|
667
671
|
verify_gemini_env_file
|
|
668
672
|
failures=0
|
|
669
673
|
enrichment_ok=0
|
|
670
|
-
if ! install_many index drain watch hotlane-brainbar; then
|
|
674
|
+
if ! install_many index t3-ingest drain watch hotlane-brainbar; then
|
|
671
675
|
failures=1
|
|
672
676
|
fi
|
|
673
677
|
if install_plist enrichment; then
|
|
@@ -707,6 +711,7 @@ case "${1:-all}" in
|
|
|
707
711
|
;;
|
|
708
712
|
remove)
|
|
709
713
|
remove_plist index
|
|
714
|
+
remove_plist t3-ingest 2>/dev/null || true
|
|
710
715
|
remove_plist enrich 2>/dev/null || true
|
|
711
716
|
remove_plist enrichment 2>/dev/null || true
|
|
712
717
|
remove_plist watch 2>/dev/null || true
|
|
@@ -730,7 +735,7 @@ case "${1:-all}" in
|
|
|
730
735
|
rm -f "$HOTLANE_BRAINBAR_DST"
|
|
731
736
|
;;
|
|
732
737
|
*)
|
|
733
|
-
echo "Usage: $0 [index|watch|enrich|enrichment|decay|drain|hotlane|repair-fts|load [name]|unload [name]|checkpoint|backup|jsonl-backup|maintenance|maintenance-nightly|maintenance-weekly|health-check|tier0-watchdog|throughput-watchdog|p0-counter|all|remove]"
|
|
738
|
+
echo "Usage: $0 [index|t3-ingest|watch|enrich|enrichment|decay|drain|hotlane|repair-fts|load [name]|unload [name]|checkpoint|backup|jsonl-backup|maintenance|maintenance-nightly|maintenance-weekly|health-check|tier0-watchdog|throughput-watchdog|p0-counter|all|remove]"
|
|
734
739
|
exit 1
|
|
735
740
|
;;
|
|
736
741
|
esac
|