nexo-brain 7.9.13 → 7.9.15

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.
@@ -18,6 +18,7 @@ Runs via launchd at 7:00 AM daily.
18
18
  """
19
19
  import json
20
20
  import hashlib
21
+ import importlib.util
21
22
  import os
22
23
  import py_compile
23
24
  import re
@@ -1901,6 +1902,31 @@ def _sync_managed_bootstraps_inline() -> list[str]:
1901
1902
  return results
1902
1903
 
1903
1904
 
1905
+ def _run_protocol_debt_drain_inline() -> dict:
1906
+ try:
1907
+ phase_path = NEXO_CODE / "scripts" / "deep-sleep" / "phase_protocol_debt_drain.py"
1908
+ spec = importlib.util.spec_from_file_location("phase_protocol_debt_drain_inline", phase_path)
1909
+ if not spec or not spec.loader:
1910
+ raise RuntimeError(f"Cannot load phase module from {phase_path}")
1911
+ module = importlib.util.module_from_spec(spec)
1912
+ spec.loader.exec_module(module)
1913
+ except Exception as exc:
1914
+ return {"ok": False, "error": f"import_failed: {exc}"}
1915
+
1916
+ try:
1917
+ report = module.run()
1918
+ except Exception as exc:
1919
+ return {"ok": False, "error": f"run_failed: {exc}"}
1920
+
1921
+ return {
1922
+ "ok": "error" not in report,
1923
+ "error": report.get("error", ""),
1924
+ "drained_count": len(report.get("drained_ids") or []),
1925
+ "requires_user_summary": report.get("requires_user_summary") or [],
1926
+ "audit_path": report.get("audit_path", ""),
1927
+ }
1928
+
1929
+
1904
1930
  def _sanitize_watchdog_registry_inline() -> dict:
1905
1931
  hash_registry = _hash_registry_path()
1906
1932
  if not hash_registry.exists():
@@ -1984,6 +2010,24 @@ def _disable_broken_personal_plugins_inline(conn: sqlite3.Connection | None) ->
1984
2010
  def run_mechanical_autofixes():
1985
2011
  conn = None
1986
2012
  try:
2013
+ debt_drain = _run_protocol_debt_drain_inline()
2014
+ if debt_drain.get("ok"):
2015
+ drained_count = int(debt_drain.get("drained_count") or 0)
2016
+ requires_user_summary = debt_drain.get("requires_user_summary") or []
2017
+ if drained_count or requires_user_summary:
2018
+ detail_bits: list[str] = []
2019
+ if drained_count:
2020
+ detail_bits.append(f"drained {drained_count} stale protocol debt item(s)")
2021
+ if requires_user_summary:
2022
+ summary = ", ".join(
2023
+ f"{item.get('debt_type')} x{int(item.get('count') or 0)}"
2024
+ for item in requires_user_summary[:4]
2025
+ )
2026
+ detail_bits.append(f"still needs user review: {summary}")
2027
+ finding("INFO", "autofix", "Self-audit protocol debt drain: " + " | ".join(detail_bits))
2028
+ elif debt_drain.get("error"):
2029
+ finding("WARN", "autofix", f"Protocol debt drain inline failed: {debt_drain['error']}")
2030
+
1987
2031
  if NEXO_DB.exists():
1988
2032
  conn = sqlite3.connect(str(NEXO_DB))
1989
2033
  conn.row_factory = sqlite3.Row
@@ -145,8 +145,8 @@ def detect_duplicates(conn):
145
145
  """Find semantically similar learnings using fastembed."""
146
146
  ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
147
147
  try:
148
- from fastembed import TextEmbedding
149
148
  import numpy as np
149
+ from local_models import build_fastembed_embedding
150
150
  except ImportError:
151
151
  print(f"[{ts}] Dedup skipped: fastembed not available")
152
152
  return []
@@ -158,7 +158,7 @@ def detect_duplicates(conn):
158
158
  if len(learnings) < 2:
159
159
  return []
160
160
 
161
- model = TextEmbedding("BAAI/bge-base-en-v1.5")
161
+ model = build_fastembed_embedding("bge-base-embeddings")
162
162
  texts = [f"{l['title']}: {l['content'][:300]}" for l in learnings]
163
163
  embeddings = list(model.embed(texts))
164
164
  embeddings = np.array(embeddings)
@@ -0,0 +1,24 @@
1
+ You are NEXO Cortex critique mode for a high-stakes decision.
2
+
3
+ Review the heuristic ranking below. Do not invent facts, risks, or constraints that are not present in the payload.
4
+
5
+ Return exactly one JSON object with this shape:
6
+ {
7
+ "recommended_choice": "candidate_name",
8
+ "confirmed_ranking": ["candidate_name_1", "candidate_name_2"],
9
+ "confidence": 0.0,
10
+ "risk_flags": ["short string"],
11
+ "disagreement_with_heuristic": false,
12
+ "reasoning_summary": "short explanation"
13
+ }
14
+
15
+ Rules:
16
+ - `recommended_choice` MUST be one of the provided candidate names.
17
+ - `confirmed_ranking` MUST contain only provided candidate names, without duplicates.
18
+ - Prefer reversible, verifiable options when risk is high or evidence is thin.
19
+ - If evidence is insufficient to overturn the heuristic winner, keep the heuristic winner.
20
+ - Use `risk_flags` for concrete concerns, not generic filler.
21
+ - Keep `confidence` between 0 and 1.
22
+
23
+ Decision payload:
24
+ [[payload_json]]