nexo-brain 7.9.25 → 7.9.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +2 -2
- package/package.json +1 -1
- package/src/agent_runner.py +26 -0
- package/src/auto_update.py +8 -3
- package/src/scripts/backfill_task_owner.py +13 -1
- package/src/scripts/deep-sleep/extract-prompt.md +2 -1
- package/src/scripts/deep-sleep/synthesize-prompt.md +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "7.9.
|
|
3
|
+
"version": "7.9.27",
|
|
4
4
|
"description": "Local cognitive runtime for Claude Code \u2014 persistent memory, overnight learning, doctor diagnostics, personal scripts, recovery-aware jobs, startup preflight, and optional dashboard/power helper.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "NEXO Brain",
|
package/README.md
CHANGED
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
|
|
19
19
|
[Watch the overview video](https://nexo-brain.com/watch/) · [Watch on YouTube](https://www.youtube.com/watch?v=i2lkGhKyVqI) · [Open the infographic](https://nexo-brain.com/assets/nexo-brain-infographic-v5.png)
|
|
20
20
|
|
|
21
|
-
Version `7.9.
|
|
21
|
+
Version `7.9.27` is the current packaged-runtime line. Patch release over `7.9.26`: server startup no longer hangs the MCP `initialize` handshake when legacy followups/reminders still need owner backfill — the synchronous startup migration now runs `--rules-only` and skips the multi-minute `LocalZeroShotClassifier` load, keeping handshake under a few seconds.
|
|
22
22
|
|
|
23
|
-
Previously in `7.9.
|
|
23
|
+
Previously in `7.9.26`: headless automation prompts now receive the operator-language contract centrally, so reports, diaries, syntheses, followups, escalations, and Deep Sleep-generated memory text follow calibration even when the underlying template is English.
|
|
24
24
|
|
|
25
25
|
Previously in `7.9.23`: Desktop lifecycle fallback diaries now enrich sparse lifecycle events from continuity snapshots, so app-exit fallback evidence preserves recent turn context even when the live agent does not answer the injected diary prompt before shutdown.
|
|
26
26
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "7.9.
|
|
3
|
+
"version": "7.9.27",
|
|
4
4
|
"mcpName": "io.github.wazionapps/nexo",
|
|
5
5
|
"description": "NEXO Brain — Shared brain for AI agents. Persistent memory, semantic RAG, natural forgetting, metacognitive guard, trust scoring, 150+ MCP tools. Works with Claude Code, Codex, Claude Desktop & any MCP client. 100% local, free.",
|
|
6
6
|
"homepage": "https://nexo-brain.com",
|
package/src/agent_runner.py
CHANGED
|
@@ -888,6 +888,30 @@ BARE_MODE_SAFE_CALLERS: frozenset[str] = frozenset({
|
|
|
888
888
|
"deep-sleep/synthesize",
|
|
889
889
|
})
|
|
890
890
|
|
|
891
|
+
MACHINE_ONLY_LANGUAGE_CONTRACT_CALLERS: frozenset[str] = frozenset({
|
|
892
|
+
"automation_probe",
|
|
893
|
+
"check_context",
|
|
894
|
+
"learning_validator",
|
|
895
|
+
})
|
|
896
|
+
|
|
897
|
+
|
|
898
|
+
def _should_apply_operator_language_contract(caller: str) -> bool:
|
|
899
|
+
clean = str(caller or "").strip()
|
|
900
|
+
if not clean:
|
|
901
|
+
return False
|
|
902
|
+
return clean not in MACHINE_ONLY_LANGUAGE_CONTRACT_CALLERS
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
def _apply_operator_language_contract(prompt: str, *, caller: str) -> str:
|
|
906
|
+
if not _should_apply_operator_language_contract(caller):
|
|
907
|
+
return prompt
|
|
908
|
+
try:
|
|
909
|
+
from operator_language import append_operator_language_contract
|
|
910
|
+
|
|
911
|
+
return append_operator_language_contract(prompt)
|
|
912
|
+
except Exception:
|
|
913
|
+
return prompt
|
|
914
|
+
|
|
891
915
|
|
|
892
916
|
def run_automation_prompt(
|
|
893
917
|
prompt: str,
|
|
@@ -972,6 +996,8 @@ def run_automation_prompt(
|
|
|
972
996
|
else:
|
|
973
997
|
append_system_prompt = enforcement_fragment
|
|
974
998
|
|
|
999
|
+
prompt = _apply_operator_language_contract(prompt, caller=caller)
|
|
1000
|
+
|
|
975
1001
|
cwd_path = Path(cwd).expanduser().resolve() if cwd else Path.cwd()
|
|
976
1002
|
run_env = _headless_env(env)
|
|
977
1003
|
extra_args = list(extra_args or [])
|
package/src/auto_update.py
CHANGED
|
@@ -2254,12 +2254,17 @@ def _maybe_backfill_task_owner() -> None:
|
|
|
2254
2254
|
return
|
|
2255
2255
|
_log(f"v6.5+: backfilling task.owner on {remaining} legacy row(s)")
|
|
2256
2256
|
env = {**os.environ, "PYTHONPATH": str(Path(__file__).resolve().parent)}
|
|
2257
|
+
# --rules-only intentionally: server startup invokes us synchronously
|
|
2258
|
+
# and any blocking >~5s breaks the MCP initialize handshake. The
|
|
2259
|
+
# regex rules already cover every legacy row correctly (worst case
|
|
2260
|
+
# falls back to 'shared'); Deep Sleep / cron can re-run without the
|
|
2261
|
+
# flag later to refine ambiguous 'shared' rows with the classifier.
|
|
2257
2262
|
r = _sp.run(
|
|
2258
|
-
[sys.executable, str(script)],
|
|
2263
|
+
[sys.executable, str(script), "--rules-only"],
|
|
2259
2264
|
env=env,
|
|
2260
2265
|
capture_output=True,
|
|
2261
2266
|
text=True,
|
|
2262
|
-
timeout=
|
|
2267
|
+
timeout=30,
|
|
2263
2268
|
)
|
|
2264
2269
|
if r.returncode == 0:
|
|
2265
2270
|
line = (r.stdout.strip().splitlines() or ["ok"])[-1]
|
|
@@ -2270,7 +2275,7 @@ def _maybe_backfill_task_owner() -> None:
|
|
|
2270
2275
|
f"{r.stderr.strip()[:200]}"
|
|
2271
2276
|
)
|
|
2272
2277
|
except _sp.TimeoutExpired:
|
|
2273
|
-
_log("task.owner backfill timed out after
|
|
2278
|
+
_log("task.owner backfill timed out after 30s (--rules-only)")
|
|
2274
2279
|
except Exception as exc:
|
|
2275
2280
|
_log(f"task.owner backfill skipped: {exc}")
|
|
2276
2281
|
|
|
@@ -265,6 +265,7 @@ def run(
|
|
|
265
265
|
*,
|
|
266
266
|
dry_run: bool,
|
|
267
267
|
do_backup: bool,
|
|
268
|
+
rules_only: bool = False,
|
|
268
269
|
) -> dict:
|
|
269
270
|
if not db_path.exists():
|
|
270
271
|
raise SystemExit(f"nexo.db not found at {db_path}")
|
|
@@ -272,7 +273,9 @@ def run(
|
|
|
272
273
|
# Load the zero-shot classifier once up front so the migration loop does
|
|
273
274
|
# not pay repeated import/init overhead. Returns None on installs without
|
|
274
275
|
# transformers/model — the regex fallback still produces correct owners.
|
|
275
|
-
|
|
276
|
+
# `rules_only` skips the load entirely so server-startup callers never
|
|
277
|
+
# block on the multi-minute mDeBERTa initialization.
|
|
278
|
+
classifier = None if rules_only else _load_local_classifier()
|
|
276
279
|
|
|
277
280
|
conn = sqlite3.connect(str(db_path))
|
|
278
281
|
try:
|
|
@@ -332,6 +335,14 @@ def main(argv=None):
|
|
|
332
335
|
ap.add_argument("--calibration", default=str(DEFAULT_CALIBRATION))
|
|
333
336
|
ap.add_argument("--dry-run", action="store_true")
|
|
334
337
|
ap.add_argument("--no-backup", action="store_true")
|
|
338
|
+
ap.add_argument(
|
|
339
|
+
"--rules-only",
|
|
340
|
+
action="store_true",
|
|
341
|
+
help="Skip the LocalZeroShotClassifier load and rely on the regex "
|
|
342
|
+
"rules. Used by server startup so MCP init never blocks on a "
|
|
343
|
+
"multi-minute model load; Deep Sleep / cron can later re-run "
|
|
344
|
+
"without this flag to refine 'shared' rows.",
|
|
345
|
+
)
|
|
335
346
|
args = ap.parse_args(argv)
|
|
336
347
|
|
|
337
348
|
report = run(
|
|
@@ -339,6 +350,7 @@ def main(argv=None):
|
|
|
339
350
|
Path(args.calibration),
|
|
340
351
|
dry_run=args.dry_run,
|
|
341
352
|
do_backup=not args.no_backup,
|
|
353
|
+
rules_only=args.rules_only,
|
|
342
354
|
)
|
|
343
355
|
print(json.dumps(report, indent=2, sort_keys=True))
|
|
344
356
|
return 0
|
|
@@ -89,6 +89,7 @@ Analyze how the session went in terms of efficiency:
|
|
|
89
89
|
## Output Format
|
|
90
90
|
|
|
91
91
|
Return ONLY valid JSON. No markdown code fences. No explanation text before or after.
|
|
92
|
+
Follow the NEXO language contract injected by the automation runner. JSON keys stay in English, but `description`, `title`, and `content` fields must be written in the operator language.
|
|
92
93
|
|
|
93
94
|
```json
|
|
94
95
|
{
|
|
@@ -276,7 +277,7 @@ Return ONLY valid JSON. No markdown code fences. No explanation text before or a
|
|
|
276
277
|
- Do NOT use any specific agent name -- refer to "the agent" throughout.
|
|
277
278
|
- If no issues found, return `{"session_id": "...", "findings": [], "protocol_summary": {...}}`.
|
|
278
279
|
- Do NOT invent problems. Empty findings are perfectly fine.
|
|
279
|
-
-
|
|
280
|
+
- Follow the NEXO language contract injected by the automation runner. The JSON keys stay in English, but `description`, `title`, and `content` fields must be written in the operator language.
|
|
280
281
|
|
|
281
282
|
## Context
|
|
282
283
|
|
|
@@ -327,7 +327,7 @@ Return ONLY valid JSON. No markdown code fences. No explanation text.
|
|
|
327
327
|
- Context packets are optional -- only create them for topics likely to continue tomorrow.
|
|
328
328
|
- Do NOT use any specific agent name -- refer to "the agent" throughout.
|
|
329
329
|
- If there are no findings worth acting on, return empty arrays. Do not invent problems.
|
|
330
|
-
-
|
|
330
|
+
- Follow the NEXO language contract injected by the automation runner. JSON keys stay in English, but descriptions, titles, agenda text, reasoning, summaries, and content fields must be written in the operator language.
|
|
331
331
|
|
|
332
332
|
## Extractions File
|
|
333
333
|
|