nexo-brain 7.34.0 → 7.35.0
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 +1 -1
- package/package.json +1 -1
- package/src/db/_hot_context.py +30 -1
- package/src/db/_schema.py +63 -0
- package/src/email_sent_events.py +7 -0
- package/src/memory_forget.py +1249 -0
- package/src/plugins/protocol.py +30 -0
- package/src/plugins/schema_abstraction.py +66 -0
- package/src/schema_abstraction.py +763 -0
- package/src/scripts/nexo-daily-self-audit.py +40 -0
- package/src/server.py +54 -0
- package/src/tools_credentials.py +60 -2
- package/tool-enforcement-map.json +66 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.35.0",
|
|
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,7 +18,7 @@
|
|
|
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.
|
|
21
|
+
Version `7.35.0` is the current packaged-runtime line. Minor release - Cognitive OS Ola 4: selective forget lets you delete a leaked secret or a wrong memory and prove it is gone (zeroed across every live store, `secure_delete=ON`) or correct a fact reversibly, recurring failure archetypes are distilled into reusable diagnostic templates primed before a matching action (strong/weak marker tiers so benign success phrasing never triggers them, guidance-only), and closing a local-only followup-runner is no longer mis-flagged as an external real-world action. Builds on v7.34.0 (working memory + self-error learning + associative graph + deep-sleep rewrite + evals).
|
|
22
22
|
|
|
23
23
|
Previously in `7.31.9`: patch release over v7.31.8 - UI release closeout now has to prove the original reported symptom was reopened with observable evidence before claiming the release is ready.
|
|
24
24
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.35.0",
|
|
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/db/_hot_context.py
CHANGED
|
@@ -570,6 +570,21 @@ def build_pre_action_context(
|
|
|
570
570
|
reminders = _find_related_items("reminders", clean_query, hours=hours, limit=4) if clean_query else []
|
|
571
571
|
followups = _find_related_items("followups", clean_query, hours=hours, limit=4) if clean_query else []
|
|
572
572
|
|
|
573
|
+
# Ola 4 SCHEMA-ABSTRACTION: if the current action CLEARLY matches a distilled
|
|
574
|
+
# recurring-incident archetype (e.g. "cron exit 0 but the tool failed
|
|
575
|
+
# silently"), prime the complete diagnosis instead of re-diagnosing from
|
|
576
|
+
# scratch. Best-effort, non-authoritative, precision-first: a template is
|
|
577
|
+
# surfaced only on a clear archetype match, never in general, and it NEVER
|
|
578
|
+
# blocks. Any failure here must not break pre-action context.
|
|
579
|
+
diagnostic_templates: list[dict] = []
|
|
580
|
+
if clean_query:
|
|
581
|
+
try:
|
|
582
|
+
import schema_abstraction as sa
|
|
583
|
+
|
|
584
|
+
diagnostic_templates = sa.match_templates_for_action(query=clean_query, limit=1)
|
|
585
|
+
except Exception:
|
|
586
|
+
diagnostic_templates = []
|
|
587
|
+
|
|
573
588
|
return {
|
|
574
589
|
"query": clean_query,
|
|
575
590
|
"context_key": clean_key,
|
|
@@ -578,7 +593,8 @@ def build_pre_action_context(
|
|
|
578
593
|
"events": events,
|
|
579
594
|
"reminders": reminders,
|
|
580
595
|
"followups": followups,
|
|
581
|
-
"
|
|
596
|
+
"diagnostic_templates": diagnostic_templates,
|
|
597
|
+
"has_matches": bool(contexts or events or reminders or followups or diagnostic_templates),
|
|
582
598
|
}
|
|
583
599
|
|
|
584
600
|
|
|
@@ -592,6 +608,19 @@ def format_pre_action_context_bundle(bundle: dict, *, compact: bool = False) ->
|
|
|
592
608
|
header += f" — query: {bundle['query'][:120]}"
|
|
593
609
|
lines.append(header)
|
|
594
610
|
|
|
611
|
+
# Ola 4: primed diagnosis from a matched recurring-incident archetype goes
|
|
612
|
+
# FIRST — the whole point is to lead with the right diagnosis.
|
|
613
|
+
templates = bundle.get("diagnostic_templates") or []
|
|
614
|
+
if templates:
|
|
615
|
+
try:
|
|
616
|
+
import schema_abstraction as sa
|
|
617
|
+
|
|
618
|
+
rendered = sa.format_templates_for_injection(templates)
|
|
619
|
+
if rendered:
|
|
620
|
+
lines.append(rendered)
|
|
621
|
+
except Exception:
|
|
622
|
+
pass
|
|
623
|
+
|
|
595
624
|
contexts = bundle.get("contexts") or []
|
|
596
625
|
if contexts:
|
|
597
626
|
lines.append("Contexts:")
|
package/src/db/_schema.py
CHANGED
|
@@ -2714,6 +2714,68 @@ def _m75_failure_prevention_ledger(conn):
|
|
|
2714
2714
|
_migrate_add_index(conn, "idx_antibody_actions_verification", "antibody_actions", "verification_status, review_due_at")
|
|
2715
2715
|
|
|
2716
2716
|
|
|
2717
|
+
def _m88_schema_abstraction_templates(conn):
|
|
2718
|
+
"""Ola 4 — diagnostic templates distilled from recurring incident archetypes.
|
|
2719
|
+
|
|
2720
|
+
NOTE (append-only migration discipline): this used to be called inline from
|
|
2721
|
+
``_m75_failure_prevention_ledger`` (as ``_m75b_...``). That meant any install
|
|
2722
|
+
already at schema v75 would NEVER create ``diagnostic_templates`` through
|
|
2723
|
+
``run_migrations()`` (v75 was already marked applied), so the table only
|
|
2724
|
+
appeared via the lazy ``_ensure_tables`` fallback. Promoting it to its own
|
|
2725
|
+
appended migration version makes a normal upgrade from v75 create the table
|
|
2726
|
+
through the standard migration path. Idempotent (``IF NOT EXISTS``), so it is
|
|
2727
|
+
a no-op on installs where ``_ensure_tables``/the old inline call already
|
|
2728
|
+
created it.
|
|
2729
|
+
|
|
2730
|
+
A diagnostic template is the destillation of a GENUINELY recurring class of
|
|
2731
|
+
incident (>= MIN_CLUSTER_SIZE distinct failure cases of the same archetype,
|
|
2732
|
+
by symptom similarity) into a reusable, complete-diagnosis-first checklist
|
|
2733
|
+
that primes the right diagnosis instantly when the archetype reappears,
|
|
2734
|
+
instead of re-diagnosing from scratch (Francisco's canonical case: "cron
|
|
2735
|
+
exit 0 but the tool failed in SILENCE").
|
|
2736
|
+
|
|
2737
|
+
Non-authoritative guidance: templates never block; they only inject a primed
|
|
2738
|
+
diagnosis into pre_action_context on a clear archetype match. Idempotent:
|
|
2739
|
+
deduped by ``template_uid`` (stable hash of archetype key). A template is
|
|
2740
|
+
minted only at high confidence; ambiguity yields nothing (a low-confidence
|
|
2741
|
+
candidate, never an active template).
|
|
2742
|
+
"""
|
|
2743
|
+
conn.execute(
|
|
2744
|
+
"""
|
|
2745
|
+
CREATE TABLE IF NOT EXISTS diagnostic_templates (
|
|
2746
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
2747
|
+
template_uid TEXT NOT NULL UNIQUE,
|
|
2748
|
+
policy_version TEXT NOT NULL DEFAULT 'schema_abstraction.v1',
|
|
2749
|
+
archetype TEXT NOT NULL,
|
|
2750
|
+
archetype_key TEXT NOT NULL,
|
|
2751
|
+
failure_type TEXT NOT NULL DEFAULT 'other',
|
|
2752
|
+
area TEXT NOT NULL DEFAULT '',
|
|
2753
|
+
symptom_pattern TEXT NOT NULL DEFAULT '',
|
|
2754
|
+
diagnosis_steps_json TEXT NOT NULL DEFAULT '[]',
|
|
2755
|
+
prevention TEXT NOT NULL DEFAULT '',
|
|
2756
|
+
match_tokens_json TEXT NOT NULL DEFAULT '[]',
|
|
2757
|
+
member_uids_json TEXT NOT NULL DEFAULT '[]',
|
|
2758
|
+
incident_count INTEGER NOT NULL DEFAULT 0,
|
|
2759
|
+
confidence REAL NOT NULL DEFAULT 0.0,
|
|
2760
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
2761
|
+
privacy_level TEXT NOT NULL DEFAULT 'normal',
|
|
2762
|
+
created_at REAL NOT NULL,
|
|
2763
|
+
updated_at REAL NOT NULL,
|
|
2764
|
+
retired_at REAL,
|
|
2765
|
+
retired_reason TEXT NOT NULL DEFAULT '',
|
|
2766
|
+
metadata_json TEXT NOT NULL DEFAULT '{}',
|
|
2767
|
+
CHECK(status IN ('active','candidate','retired','superseded')),
|
|
2768
|
+
CHECK(privacy_level IN ('public','normal','private','sensitive','secret')),
|
|
2769
|
+
CHECK(incident_count >= 0),
|
|
2770
|
+
CHECK(confidence >= 0.0 AND confidence <= 1.0)
|
|
2771
|
+
)
|
|
2772
|
+
"""
|
|
2773
|
+
)
|
|
2774
|
+
_migrate_add_index(conn, "idx_diagnostic_templates_archetype", "diagnostic_templates", "archetype_key")
|
|
2775
|
+
_migrate_add_index(conn, "idx_diagnostic_templates_status", "diagnostic_templates", "status, area")
|
|
2776
|
+
_migrate_add_index(conn, "idx_diagnostic_templates_type", "diagnostic_templates", "failure_type, status")
|
|
2777
|
+
|
|
2778
|
+
|
|
2717
2779
|
def _m76_semantic_layers(conn):
|
|
2718
2780
|
"""SemanticLayers cache for compact, source-backed continuity.
|
|
2719
2781
|
|
|
@@ -3402,6 +3464,7 @@ MIGRATIONS = [
|
|
|
3402
3464
|
(85, "eval_runs", _m85_eval_runs),
|
|
3403
3465
|
(86, "resolution_cache", _m86_resolution_cache),
|
|
3404
3466
|
(87, "resolution_cache_content_snapshot", _m87_resolution_cache_content_snapshot),
|
|
3467
|
+
(88, "schema_abstraction_templates", _m88_schema_abstraction_templates),
|
|
3405
3468
|
]
|
|
3406
3469
|
|
|
3407
3470
|
|
package/src/email_sent_events.py
CHANGED
|
@@ -8,6 +8,7 @@ sent even when the send path did not originate from an inbound email row.
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
|
+
import os
|
|
11
12
|
import sqlite3
|
|
12
13
|
from datetime import datetime, timedelta
|
|
13
14
|
from pathlib import Path
|
|
@@ -43,6 +44,12 @@ RECENT_SENT_EMAILS_TITLE = "EMAILS ENVIADOS ULTIMAS 24H POR LA OPERATIVA"
|
|
|
43
44
|
|
|
44
45
|
|
|
45
46
|
def sent_email_db_path() -> Path:
|
|
47
|
+
# NEXO_EMAIL_DB lets tests (and the selective-forget live-DB enumerator)
|
|
48
|
+
# isolate / discover the email store deterministically without rewiring
|
|
49
|
+
# NEXO_HOME. Falls back to the canonical runtime location.
|
|
50
|
+
override = os.environ.get("NEXO_EMAIL_DB", "").strip()
|
|
51
|
+
if override:
|
|
52
|
+
return Path(override).expanduser()
|
|
46
53
|
return paths.nexo_email_dir() / "nexo-email.db"
|
|
47
54
|
|
|
48
55
|
|