nexo-brain 2.3.0 → 2.3.1

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.
Files changed (287) hide show
  1. package/README.md +1 -1
  2. package/package.json +6 -3
  3. package/src/auto_update.py +1 -0
  4. package/src/crons/sync.py +1 -2
  5. package/src/db/_core.py +1 -0
  6. package/src/db/_entities.py +1 -0
  7. package/src/db/_episodic.py +1 -0
  8. package/src/db/_learnings.py +1 -0
  9. package/src/db/_reminders.py +1 -0
  10. package/src/db/_sessions.py +1 -0
  11. package/src/db/_skills.py +1 -0
  12. package/src/plugin_loader.py +1 -0
  13. package/src/plugins/update.py +1 -0
  14. package/src/scripts/deep-sleep/apply_findings.py +1 -0
  15. package/src/scripts/deep-sleep/collect.py +1 -0
  16. package/src/scripts/deep-sleep/extract.py +1 -0
  17. package/src/scripts/deep-sleep/synthesize.py +1 -0
  18. package/src/scripts/nexo-learning-housekeep.py +1 -0
  19. package/src/scripts/nexo-watchdog.sh +19 -11
  20. package/src/server.py +1 -0
  21. package/src/tools_coordination.py +1 -0
  22. package/src/tools_sessions.py +1 -0
  23. package/scripts/migrate-to-unified 2.sh +0 -813
  24. package/scripts/migrate-to-unified.sh +0 -813
  25. package/scripts/migrate-v1.5-to-v1.6 2.py +0 -778
  26. package/scripts/migrate-v1.5-to-v1.6.py +0 -778
  27. package/scripts/migrate-v1.7-to-v1.8 2.py +0 -214
  28. package/scripts/migrate-v1.7-to-v1.8.py +0 -214
  29. package/scripts/nexo-preflight.sh +0 -236
  30. package/scripts/pre-commit-check 2.sh +0 -55
  31. package/scripts/pre-commit-check.sh +0 -55
  32. package/src/__pycache__/auto_close_sessions.cpython-314.pyc +0 -0
  33. package/src/__pycache__/auto_update.cpython-310.pyc +0 -0
  34. package/src/__pycache__/hnsw_index.cpython-310.pyc +0 -0
  35. package/src/__pycache__/hnsw_index.cpython-314.pyc +0 -0
  36. package/src/__pycache__/kg_populate.cpython-310.pyc +0 -0
  37. package/src/__pycache__/knowledge_graph.cpython-310.pyc +0 -0
  38. package/src/__pycache__/plugin_loader.cpython-310.pyc +0 -0
  39. package/src/__pycache__/plugin_loader.cpython-314.pyc +0 -0
  40. package/src/__pycache__/tools_coordination.cpython-310.pyc +0 -0
  41. package/src/__pycache__/tools_credentials.cpython-310.pyc +0 -0
  42. package/src/__pycache__/tools_learnings.cpython-310.pyc +0 -0
  43. package/src/__pycache__/tools_menu.cpython-310.pyc +0 -0
  44. package/src/__pycache__/tools_reminders.cpython-310.pyc +0 -0
  45. package/src/__pycache__/tools_reminders_crud.cpython-310.pyc +0 -0
  46. package/src/__pycache__/tools_sessions.cpython-310.pyc +0 -0
  47. package/src/__pycache__/tools_task_history.cpython-310.pyc +0 -0
  48. package/src/auto_close_sessions 2.py +0 -159
  49. package/src/auto_update 2.py +0 -634
  50. package/src/claim_graph 2.py +0 -323
  51. package/src/cognitive/__init__ 2.py +0 -62
  52. package/src/cognitive/__pycache__/__init__.cpython-310.pyc +0 -0
  53. package/src/cognitive/__pycache__/__init__.cpython-312.pyc +0 -0
  54. package/src/cognitive/__pycache__/__init__.cpython-314.pyc +0 -0
  55. package/src/cognitive/__pycache__/_core.cpython-310.pyc +0 -0
  56. package/src/cognitive/__pycache__/_core.cpython-312.pyc +0 -0
  57. package/src/cognitive/__pycache__/_core.cpython-314.pyc +0 -0
  58. package/src/cognitive/__pycache__/_decay.cpython-310.pyc +0 -0
  59. package/src/cognitive/__pycache__/_decay.cpython-312.pyc +0 -0
  60. package/src/cognitive/__pycache__/_decay.cpython-314.pyc +0 -0
  61. package/src/cognitive/__pycache__/_ingest.cpython-310.pyc +0 -0
  62. package/src/cognitive/__pycache__/_ingest.cpython-312.pyc +0 -0
  63. package/src/cognitive/__pycache__/_ingest.cpython-314.pyc +0 -0
  64. package/src/cognitive/__pycache__/_memory.cpython-310.pyc +0 -0
  65. package/src/cognitive/__pycache__/_memory.cpython-312.pyc +0 -0
  66. package/src/cognitive/__pycache__/_memory.cpython-314.pyc +0 -0
  67. package/src/cognitive/__pycache__/_search.cpython-310.pyc +0 -0
  68. package/src/cognitive/__pycache__/_search.cpython-312.pyc +0 -0
  69. package/src/cognitive/__pycache__/_search.cpython-314.pyc +0 -0
  70. package/src/cognitive/__pycache__/_trust.cpython-310.pyc +0 -0
  71. package/src/cognitive/__pycache__/_trust.cpython-312.pyc +0 -0
  72. package/src/cognitive/__pycache__/_trust.cpython-314.pyc +0 -0
  73. package/src/cognitive/_core 2.py +0 -567
  74. package/src/cognitive/_decay 2.py +0 -382
  75. package/src/cognitive/_ingest 2.py +0 -892
  76. package/src/cognitive/_memory 2.py +0 -912
  77. package/src/cognitive/_search 2.py +0 -949
  78. package/src/cognitive/_trust 2.py +0 -464
  79. package/src/crons/__pycache__/sync.cpython-314.pyc +0 -0
  80. package/src/crons/manifest 2.json +0 -106
  81. package/src/crons/sync 2.py +0 -217
  82. package/src/dashboard/__init__ 2.py +0 -0
  83. package/src/dashboard/__pycache__/__init__.cpython-310.pyc +0 -0
  84. package/src/dashboard/__pycache__/app.cpython-310.pyc +0 -0
  85. package/src/dashboard/app 2.py +0 -789
  86. package/src/db/__init__ 2.py +0 -89
  87. package/src/db/__pycache__/__init__.cpython-310.pyc +0 -0
  88. package/src/db/__pycache__/__init__.cpython-312.pyc +0 -0
  89. package/src/db/__pycache__/__init__.cpython-314.pyc +0 -0
  90. package/src/db/__pycache__/_core.cpython-310.pyc +0 -0
  91. package/src/db/__pycache__/_core.cpython-312.pyc +0 -0
  92. package/src/db/__pycache__/_core.cpython-314.pyc +0 -0
  93. package/src/db/__pycache__/_credentials.cpython-310.pyc +0 -0
  94. package/src/db/__pycache__/_credentials.cpython-312.pyc +0 -0
  95. package/src/db/__pycache__/_credentials.cpython-314.pyc +0 -0
  96. package/src/db/__pycache__/_cron_runs.cpython-310.pyc +0 -0
  97. package/src/db/__pycache__/_cron_runs.cpython-314.pyc +0 -0
  98. package/src/db/__pycache__/_entities.cpython-310.pyc +0 -0
  99. package/src/db/__pycache__/_entities.cpython-312.pyc +0 -0
  100. package/src/db/__pycache__/_entities.cpython-314.pyc +0 -0
  101. package/src/db/__pycache__/_episodic.cpython-310.pyc +0 -0
  102. package/src/db/__pycache__/_episodic.cpython-312.pyc +0 -0
  103. package/src/db/__pycache__/_episodic.cpython-314.pyc +0 -0
  104. package/src/db/__pycache__/_evolution.cpython-310.pyc +0 -0
  105. package/src/db/__pycache__/_evolution.cpython-312.pyc +0 -0
  106. package/src/db/__pycache__/_evolution.cpython-314.pyc +0 -0
  107. package/src/db/__pycache__/_fts.cpython-310.pyc +0 -0
  108. package/src/db/__pycache__/_fts.cpython-312.pyc +0 -0
  109. package/src/db/__pycache__/_fts.cpython-314.pyc +0 -0
  110. package/src/db/__pycache__/_learnings.cpython-310.pyc +0 -0
  111. package/src/db/__pycache__/_learnings.cpython-312.pyc +0 -0
  112. package/src/db/__pycache__/_learnings.cpython-314.pyc +0 -0
  113. package/src/db/__pycache__/_reminders.cpython-310.pyc +0 -0
  114. package/src/db/__pycache__/_reminders.cpython-312.pyc +0 -0
  115. package/src/db/__pycache__/_reminders.cpython-314.pyc +0 -0
  116. package/src/db/__pycache__/_schema.cpython-310.pyc +0 -0
  117. package/src/db/__pycache__/_schema.cpython-312.pyc +0 -0
  118. package/src/db/__pycache__/_schema.cpython-314.pyc +0 -0
  119. package/src/db/__pycache__/_sessions.cpython-310.pyc +0 -0
  120. package/src/db/__pycache__/_sessions.cpython-312.pyc +0 -0
  121. package/src/db/__pycache__/_sessions.cpython-314.pyc +0 -0
  122. package/src/db/__pycache__/_skills.cpython-310.pyc +0 -0
  123. package/src/db/__pycache__/_skills.cpython-312.pyc +0 -0
  124. package/src/db/__pycache__/_skills.cpython-314.pyc +0 -0
  125. package/src/db/__pycache__/_tasks.cpython-310.pyc +0 -0
  126. package/src/db/__pycache__/_tasks.cpython-312.pyc +0 -0
  127. package/src/db/__pycache__/_tasks.cpython-314.pyc +0 -0
  128. package/src/db/_core 2.py +0 -417
  129. package/src/db/_credentials 2.py +0 -124
  130. package/src/db/_entities 2.py +0 -178
  131. package/src/db/_episodic 2.py +0 -738
  132. package/src/db/_evolution 2.py +0 -54
  133. package/src/db/_fts 2.py +0 -406
  134. package/src/db/_learnings 2.py +0 -168
  135. package/src/db/_reminders 2.py +0 -338
  136. package/src/db/_schema 2.py +0 -364
  137. package/src/db/_sessions 2.py +0 -300
  138. package/src/db/_tasks 2.py +0 -91
  139. package/src/evolution_cycle 2.py +0 -266
  140. package/src/hnsw_index 2.py +0 -254
  141. package/src/hooks/auto_capture 2.py +0 -208
  142. package/src/hooks/caffeinate-guard 2.sh +0 -8
  143. package/src/hooks/capture-session 2.sh +0 -21
  144. package/src/hooks/capture-tool-logs 2.sh +0 -127
  145. package/src/hooks/daily-briefing-check 2.sh +0 -33
  146. package/src/hooks/inbox-hook 2.sh +0 -76
  147. package/src/hooks/post-compact 2.sh +0 -148
  148. package/src/hooks/pre-compact 2.sh +0 -151
  149. package/src/hooks/session-start 2.sh +0 -268
  150. package/src/hooks/session-stop 2.sh +0 -140
  151. package/src/kg_populate 2.py +0 -290
  152. package/src/knowledge_graph 2.py +0 -257
  153. package/src/maintenance 2.py +0 -59
  154. package/src/migrate_embeddings 2.py +0 -122
  155. package/src/plugin_loader 2.py +0 -202
  156. package/src/plugins/__init__ 2.py +0 -0
  157. package/src/plugins/__pycache__/__init__ 2.cpython-310.pyc +0 -0
  158. package/src/plugins/__pycache__/__init__.cpython-310.pyc +0 -0
  159. package/src/plugins/__pycache__/__init__.cpython-314.pyc +0 -0
  160. package/src/plugins/__pycache__/adaptive_mode 2.cpython-310.pyc +0 -0
  161. package/src/plugins/__pycache__/adaptive_mode.cpython-310.pyc +0 -0
  162. package/src/plugins/__pycache__/adaptive_mode.cpython-314.pyc +0 -0
  163. package/src/plugins/__pycache__/agents 2.cpython-310.pyc +0 -0
  164. package/src/plugins/__pycache__/agents.cpython-310.pyc +0 -0
  165. package/src/plugins/__pycache__/artifact_registry 2.cpython-310.pyc +0 -0
  166. package/src/plugins/__pycache__/artifact_registry.cpython-310.pyc +0 -0
  167. package/src/plugins/__pycache__/backup 2.cpython-310.pyc +0 -0
  168. package/src/plugins/__pycache__/backup.cpython-310.pyc +0 -0
  169. package/src/plugins/__pycache__/cognitive_memory 2.cpython-310.pyc +0 -0
  170. package/src/plugins/__pycache__/cognitive_memory.cpython-310.pyc +0 -0
  171. package/src/plugins/__pycache__/core_rules 2.cpython-310.pyc +0 -0
  172. package/src/plugins/__pycache__/core_rules.cpython-310.pyc +0 -0
  173. package/src/plugins/__pycache__/cortex 2.cpython-310.pyc +0 -0
  174. package/src/plugins/__pycache__/cortex.cpython-310.pyc +0 -0
  175. package/src/plugins/__pycache__/entities 2.cpython-310.pyc +0 -0
  176. package/src/plugins/__pycache__/entities.cpython-310.pyc +0 -0
  177. package/src/plugins/__pycache__/episodic_memory 2.cpython-310.pyc +0 -0
  178. package/src/plugins/__pycache__/episodic_memory.cpython-310.pyc +0 -0
  179. package/src/plugins/__pycache__/evolution 2.cpython-310.pyc +0 -0
  180. package/src/plugins/__pycache__/evolution.cpython-310.pyc +0 -0
  181. package/src/plugins/__pycache__/guard 2.cpython-310.pyc +0 -0
  182. package/src/plugins/__pycache__/guard.cpython-310.pyc +0 -0
  183. package/src/plugins/__pycache__/knowledge_graph_tools 2.cpython-310.pyc +0 -0
  184. package/src/plugins/__pycache__/knowledge_graph_tools.cpython-310.pyc +0 -0
  185. package/src/plugins/__pycache__/preferences 2.cpython-310.pyc +0 -0
  186. package/src/plugins/__pycache__/preferences.cpython-310.pyc +0 -0
  187. package/src/plugins/__pycache__/schedule.cpython-310.pyc +0 -0
  188. package/src/plugins/__pycache__/schedule.cpython-314.pyc +0 -0
  189. package/src/plugins/__pycache__/skills.cpython-310.pyc +0 -0
  190. package/src/plugins/__pycache__/skills.cpython-314.pyc +0 -0
  191. package/src/plugins/__pycache__/update 2.cpython-310.pyc +0 -0
  192. package/src/plugins/__pycache__/update.cpython-310.pyc +0 -0
  193. package/src/plugins/adaptive_mode 2.py +0 -805
  194. package/src/plugins/agents 2.py +0 -52
  195. package/src/plugins/artifact_registry 2.py +0 -450
  196. package/src/plugins/backup 2.py +0 -104
  197. package/src/plugins/cognitive_memory 2.py +0 -564
  198. package/src/plugins/core_rules 2.py +0 -252
  199. package/src/plugins/cortex 2.py +0 -299
  200. package/src/plugins/entities 2.py +0 -67
  201. package/src/plugins/episodic_memory 2.py +0 -533
  202. package/src/plugins/evolution 2.py +0 -115
  203. package/src/plugins/guard 2.py +0 -746
  204. package/src/plugins/knowledge_graph_tools 2.py +0 -105
  205. package/src/plugins/preferences 2.py +0 -47
  206. package/src/plugins/update 2.py +0 -256
  207. package/src/requirements 2.txt +0 -12
  208. package/src/rules/__init__ 2.py +0 -0
  209. package/src/rules/core-rules 2.json +0 -331
  210. package/src/rules/migrate 2.py +0 -207
  211. package/src/scripts/__pycache__/nexo-auto-update.cpython-314.pyc +0 -0
  212. package/src/scripts/__pycache__/nexo-catchup.cpython-314.pyc +0 -0
  213. package/src/scripts/__pycache__/nexo-cognitive-decay.cpython-314.pyc +0 -0
  214. package/src/scripts/__pycache__/nexo-daily-self-audit.cpython-314.pyc +0 -0
  215. package/src/scripts/__pycache__/nexo-evolution-run.cpython-314.pyc +0 -0
  216. package/src/scripts/__pycache__/nexo-followup-hygiene.cpython-314.pyc +0 -0
  217. package/src/scripts/__pycache__/nexo-immune.cpython-314.pyc +0 -0
  218. package/src/scripts/__pycache__/nexo-install.cpython-314.pyc +0 -0
  219. package/src/scripts/__pycache__/nexo-learning-housekeep.cpython-314.pyc +0 -0
  220. package/src/scripts/__pycache__/nexo-learning-validator.cpython-314.pyc +0 -0
  221. package/src/scripts/__pycache__/nexo-migrate.cpython-314.pyc +0 -0
  222. package/src/scripts/__pycache__/nexo-postmortem-consolidator.cpython-314.pyc +0 -0
  223. package/src/scripts/__pycache__/nexo-pre-commit.cpython-314.pyc +0 -0
  224. package/src/scripts/__pycache__/nexo-proactive-dashboard.cpython-314.pyc +0 -0
  225. package/src/scripts/__pycache__/nexo-reflection.cpython-314.pyc +0 -0
  226. package/src/scripts/__pycache__/nexo-runtime-preflight.cpython-314.pyc +0 -0
  227. package/src/scripts/__pycache__/nexo-send-email.cpython-314.pyc +0 -0
  228. package/src/scripts/__pycache__/nexo-send-reply.cpython-314.pyc +0 -0
  229. package/src/scripts/__pycache__/nexo-sleep.cpython-314.pyc +0 -0
  230. package/src/scripts/__pycache__/nexo-synthesis.cpython-314.pyc +0 -0
  231. package/src/scripts/__pycache__/nexo-watchdog-smoke.cpython-314.pyc +0 -0
  232. package/src/scripts/check-context 2.py +0 -264
  233. package/src/scripts/nexo-auto-update 2.py +0 -6
  234. package/src/scripts/nexo-backup 2.sh +0 -25
  235. package/src/scripts/nexo-brain-activation 2.sh +0 -140
  236. package/src/scripts/nexo-catchup 2.py +0 -242
  237. package/src/scripts/nexo-cognitive-decay 2.py +0 -182
  238. package/src/scripts/nexo-daily-self-audit 2.py +0 -552
  239. package/src/scripts/nexo-deep-sleep 2.sh +0 -97
  240. package/src/scripts/nexo-evolution-run 2.py +0 -597
  241. package/src/scripts/nexo-followup-hygiene 2.py +0 -112
  242. package/src/scripts/nexo-github-monitor 2.py +0 -256
  243. package/src/scripts/nexo-immune 2.py +0 -927
  244. package/src/scripts/nexo-inbox-hook 2.sh +0 -74
  245. package/src/scripts/nexo-install 2.py +0 -6
  246. package/src/scripts/nexo-learning-housekeep 2.py +0 -245
  247. package/src/scripts/nexo-learning-validator 2.py +0 -207
  248. package/src/scripts/nexo-migrate 2.py +0 -232
  249. package/src/scripts/nexo-postmortem-consolidator 2.py +0 -421
  250. package/src/scripts/nexo-pre-commit 2.py +0 -120
  251. package/src/scripts/nexo-prevent-sleep 2.sh +0 -29
  252. package/src/scripts/nexo-proactive-dashboard 2.py +0 -345
  253. package/src/scripts/nexo-reflection 2.py +0 -253
  254. package/src/scripts/nexo-runtime-preflight 2.py +0 -274
  255. package/src/scripts/nexo-send-email 2.py +0 -25
  256. package/src/scripts/nexo-send-email.py +0 -25
  257. package/src/scripts/nexo-send-reply 2.py +0 -178
  258. package/src/scripts/nexo-send-reply.py +0 -178
  259. package/src/scripts/nexo-sleep 2.py +0 -592
  260. package/src/scripts/nexo-snapshot-restore 2.sh +0 -35
  261. package/src/scripts/nexo-synthesis 2.py +0 -253
  262. package/src/scripts/nexo-tcc-approve 2.sh +0 -79
  263. package/src/scripts/nexo-update 2.sh +0 -161
  264. package/src/scripts/nexo-watchdog 2.sh +0 -878
  265. package/src/scripts/nexo-watchdog-smoke 2.py +0 -119
  266. package/src/server 2.py +0 -733
  267. package/src/storage_router 2.py +0 -32
  268. package/src/tools_coordination 2.py +0 -102
  269. package/src/tools_credentials 2.py +0 -68
  270. package/src/tools_learnings 2.py +0 -220
  271. package/src/tools_menu 2.py +0 -227
  272. package/src/tools_reminders 2.py +0 -86
  273. package/src/tools_reminders_crud 2.py +0 -159
  274. package/src/tools_sessions 2.py +0 -476
  275. package/src/tools_task_history 2.py +0 -57
  276. package/templates/CLAUDE.md 2.template +0 -63
  277. package/templates/openclaw 2.json +0 -13
  278. package/tests/__init__ 2.py +0 -0
  279. package/tests/__init__.py +0 -0
  280. package/tests/conftest 2.py +0 -71
  281. package/tests/conftest.py +0 -71
  282. package/tests/test_cognitive 2.py +0 -205
  283. package/tests/test_cognitive.py +0 -205
  284. package/tests/test_knowledge_graph 2.py +0 -140
  285. package/tests/test_knowledge_graph.py +0 -140
  286. package/tests/test_migrations 2.py +0 -137
  287. package/tests/test_migrations.py +0 -137
@@ -1,464 +0,0 @@
1
- """NEXO Cognitive — Trust scoring, sentiment, dissonance."""
2
- import re
3
- import numpy as np
4
- from datetime import datetime, timedelta
5
- from cognitive._core import _get_db, embed, cosine_similarity, _blob_to_array
6
- from cognitive._core import POSITIVE_SIGNALS, NEGATIVE_SIGNALS, URGENCY_SIGNALS
7
-
8
-
9
- # Trust score events — default deltas (overridable via trust_event_config table)
10
- _DEFAULT_TRUST_EVENTS = {
11
- # Positive
12
- "explicit_thanks": +3,
13
- "delegation": +2, # user delegates new task without micromanaging
14
- "paradigm_shift": +2, # user teaches, NEXO learns
15
- "sibling_detected": +3, # NEXO avoided context error on its own
16
- "proactive_action": +2, # NEXO did something useful without being asked
17
- # Negative
18
- "correction": -3, # user corrects NEXO
19
- "repeated_error": -7, # Error on something NEXO already had a learning for
20
- "override": -5, # NEXO's memory was wrong
21
- "correction_fatigue": -10, # Same memory corrected 3+ times
22
- "forgot_followup": -4, # Forgot to mark followup or execute it
23
- }
24
-
25
- # Lazy-loaded from DB (trust_event_config table overrides defaults)
26
- _trust_events_cache = None
27
- _trust_events_cache_ts = 0
28
-
29
-
30
- def get_trust_events() -> dict:
31
- """Get trust events with deltas. DB overrides take priority over defaults."""
32
- global _trust_events_cache, _trust_events_cache_ts
33
- import time
34
- now = time.time()
35
- # Cache for 60s to avoid constant DB reads
36
- if _trust_events_cache is not None and (now - _trust_events_cache_ts) < 60:
37
- return _trust_events_cache
38
-
39
- events = dict(_DEFAULT_TRUST_EVENTS)
40
- try:
41
- db = _get_db()
42
- db.execute("""
43
- CREATE TABLE IF NOT EXISTS trust_event_config (
44
- event TEXT PRIMARY KEY,
45
- delta REAL NOT NULL,
46
- description TEXT DEFAULT '',
47
- updated_at TEXT DEFAULT (datetime('now'))
48
- )
49
- """)
50
- rows = db.execute("SELECT event, delta FROM trust_event_config").fetchall()
51
- for r in rows:
52
- events[r[0]] = r[1]
53
- except Exception:
54
- pass
55
- _trust_events_cache = events
56
- _trust_events_cache_ts = now
57
- return events
58
-
59
- # For backward compat — code that reads TRUST_EVENTS directly
60
- TRUST_EVENTS = _DEFAULT_TRUST_EVENTS
61
-
62
- # Auto-detection patterns for trust events from user text
63
- # Each pattern: (event_name, keywords/phrases that trigger it, min_matches)
64
- TRUST_AUTO_PATTERNS = {
65
- "explicit_thanks": {
66
- "patterns": [
67
- "gracias", "buen trabajo", "bien hecho", "perfecto", "genial",
68
- "excelente", "fenomenal", "great job", "nice work", "thank",
69
- "thanks", "awesome", "amazing", "love it", "me encanta",
70
- ],
71
- "min_matches": 1,
72
- },
73
- "correction": {
74
- "patterns": [
75
- "ya te dije", "ya te lo dije", "otra vez", "te he dicho",
76
- "no es así", "eso no", "mal", "incorrecto", "equivocado",
77
- "no no no", "that's wrong", "te aviso", "te avisé",
78
- "2ª vez", "segunda vez", "te lo repito",
79
- ],
80
- "min_matches": 1,
81
- },
82
- "repeated_error": {
83
- "patterns": [
84
- "otra vez lo mismo", "siempre igual", "ya te lo dije antes",
85
- "cuántas veces", "no aprendes", "same mistake", "again the same",
86
- "ya van", "es la 2", "es la 3", "ya te avisé",
87
- ],
88
- "min_matches": 1,
89
- },
90
- "delegation": {
91
- "patterns": [
92
- "encárgate", "hazlo tú", "dale tú", "te lo dejo",
93
- "manéjalo", "resuélvelo", "handle it", "take care of",
94
- "you decide", "tú decides", "lo que veas", "como veas",
95
- ],
96
- "min_matches": 1,
97
- },
98
- }
99
-
100
-
101
- def auto_detect_trust_events(text: str) -> list[dict]:
102
- """Detect trust events from user text. Returns list of {event, delta, reason}.
103
-
104
- Called automatically by heartbeat. Only fires once per event per heartbeat
105
- to avoid double-counting.
106
- """
107
- if not text or len(text.strip()) < 5:
108
- return []
109
-
110
- text_lower = text.lower()
111
- events = get_trust_events()
112
- detected = []
113
-
114
- for event_name, config in TRUST_AUTO_PATTERNS.items():
115
- matches = [p for p in config["patterns"] if p in text_lower]
116
- if len(matches) >= config["min_matches"]:
117
- delta = events.get(event_name, _DEFAULT_TRUST_EVENTS.get(event_name, 0))
118
- detected.append({
119
- "event": event_name,
120
- "delta": delta,
121
- "reason": f"auto-detected: {', '.join(matches[:3])}",
122
- })
123
-
124
- # Priority: if repeated_error detected, remove correction (it's a superset)
125
- event_names = {d["event"] for d in detected}
126
- if "repeated_error" in event_names and "correction" in event_names:
127
- detected = [d for d in detected if d["event"] != "correction"]
128
- # If explicit_thanks and delegation both detected, keep both (they're independent)
129
-
130
- return detected
131
-
132
- def detect_dissonance(new_instruction: str, min_score: float = 0.65) -> list[dict]:
133
- """Detect cognitive dissonance: find LTM memories that contradict a new instruction.
134
-
135
- When user gives a new instruction that conflicts with established LTM memories
136
- (strength > 0.8), this function surfaces the conflict so NEXO can verbalize it
137
- rather than silently obeying or silently resisting.
138
-
139
- Args:
140
- new_instruction: The new instruction or preference from user
141
- min_score: Minimum cosine similarity to consider as potential conflict
142
-
143
- Returns:
144
- List of conflicting memories with their strength and content
145
- """
146
- db = _get_db()
147
- query_vec = embed(new_instruction[:500])
148
- if np.linalg.norm(query_vec) == 0:
149
- return []
150
-
151
- rows = db.execute(
152
- "SELECT id, content, embedding, source_type, domain, strength, access_count FROM ltm_memories WHERE is_dormant = 0 AND strength > 0.8"
153
- ).fetchall()
154
-
155
- conflicts = []
156
- for row in rows:
157
- vec = _blob_to_array(row["embedding"])
158
- score = cosine_similarity(query_vec, vec)
159
- if score >= min_score:
160
- conflicts.append({
161
- "memory_id": row["id"],
162
- "content": row["content"],
163
- "source_type": row["source_type"],
164
- "domain": row["domain"],
165
- "strength": row["strength"],
166
- "access_count": row["access_count"],
167
- "similarity": round(score, 3),
168
- })
169
-
170
- conflicts.sort(key=lambda x: x["similarity"], reverse=True)
171
- return conflicts[:5]
172
-
173
-
174
- def resolve_dissonance(memory_id: int, resolution: str, context: str = "") -> str:
175
- """Resolve a cognitive dissonance by applying user's decision.
176
-
177
- Args:
178
- memory_id: The LTM memory that conflicts with the new instruction
179
- resolution: One of:
180
- - 'paradigm_shift': user changed his mind permanently. Decay old memory,
181
- new instruction becomes the standard.
182
- - 'exception': This is a one-time override. Keep old memory as standard.
183
- - 'override': Old memory was wrong. Mark as corrupted and decay to dormant.
184
-
185
- Returns:
186
- Status message
187
- """
188
- db = _get_db()
189
- row = db.execute("SELECT * FROM ltm_memories WHERE id = ?", (memory_id,)).fetchone()
190
- if not row:
191
- return f"Memory #{memory_id} not found."
192
-
193
- now = datetime.utcnow().isoformat()
194
-
195
- if resolution == "paradigm_shift":
196
- # Instant decay to 0.3, will naturally fade. New instruction takes over.
197
- db.execute(
198
- "UPDATE ltm_memories SET strength = 0.3, last_accessed = ? WHERE id = ?",
199
- (now, memory_id)
200
- )
201
- msg = f"Paradigm shift: Memory #{memory_id} decayed to 0.3. New standard will replace it."
202
-
203
- elif resolution == "exception":
204
- # Keep memory as-is, just log the exception
205
- msg = f"Exception noted: Memory #{memory_id} remains standard. One-time override applied."
206
-
207
- elif resolution == "override":
208
- # Memory was wrong — mark as corrupted/dormant
209
- db.execute(
210
- "UPDATE ltm_memories SET strength = 0.05, is_dormant = 1, last_accessed = ? WHERE id = ?",
211
- (now, memory_id)
212
- )
213
- msg = f"Override: Memory #{memory_id} marked corrupted and dormant."
214
-
215
- else:
216
- return f"Unknown resolution: {resolution}. Use 'paradigm_shift', 'exception', or 'override'."
217
-
218
- # Log the correction
219
- db.execute(
220
- "INSERT INTO memory_corrections (memory_id, store, correction_type, context) VALUES (?, 'ltm', ?, ?)",
221
- (memory_id, resolution, context[:500])
222
- )
223
- db.commit()
224
-
225
- return msg
226
-
227
-
228
- def check_correction_fatigue() -> list[dict]:
229
- """Find memories corrected 3+ times in the last 7 days — mark as 'under review'.
230
-
231
- These memories are unreliable: user keeps overriding them, suggesting
232
- the memory itself may be wrong or outdated.
233
-
234
- Returns:
235
- List of memories that should be flagged as unreliable
236
- """
237
- db = _get_db()
238
- cutoff = (datetime.utcnow() - timedelta(days=7)).isoformat()
239
-
240
- rows = db.execute("""
241
- SELECT memory_id, COUNT(*) as correction_count,
242
- GROUP_CONCAT(correction_type) as types
243
- FROM memory_corrections
244
- WHERE created_at >= ? AND store = 'ltm'
245
- GROUP BY memory_id
246
- HAVING COUNT(*) >= 3
247
- """, (cutoff,)).fetchall()
248
-
249
- fatigued = []
250
- for row in rows:
251
- mem = db.execute(
252
- "SELECT content, strength, source_type, domain FROM ltm_memories WHERE id = ?",
253
- (row["memory_id"],)
254
- ).fetchone()
255
- if mem:
256
- fatigued.append({
257
- "memory_id": row["memory_id"],
258
- "corrections_7d": row["correction_count"],
259
- "types": row["types"],
260
- "content": mem["content"][:200],
261
- "strength": mem["strength"],
262
- "source_type": mem["source_type"],
263
- "domain": mem["domain"],
264
- })
265
-
266
- # Auto-mark as under review: decay strength to 0.2
267
- db.execute(
268
- "UPDATE ltm_memories SET strength = MIN(strength, 0.2), tags = CASE WHEN tags LIKE '%under_review%' THEN tags ELSE tags || ',under_review' END WHERE id = ?",
269
- (row["memory_id"],)
270
- )
271
-
272
- if fatigued:
273
- db.commit()
274
-
275
- return fatigued
276
-
277
- def detect_sentiment(text: str) -> dict:
278
- """Analyze user's text for sentiment signals.
279
-
280
- Returns detected sentiment, intensity, and action guidance for NEXO.
281
- Not a model — keyword + heuristic based. Fast and deterministic.
282
- """
283
- if not text:
284
- return {"sentiment": "neutral", "intensity": 0.5, "signals": [], "guidance": ""}
285
-
286
- text_lower = text.lower()
287
- words = set(text_lower.split())
288
-
289
- positive_hits = [s for s in POSITIVE_SIGNALS if s in text_lower]
290
- negative_hits = [s for s in NEGATIVE_SIGNALS if s in text_lower]
291
- urgency_hits = [s for s in URGENCY_SIGNALS if s in text_lower]
292
-
293
- # Heuristics
294
- is_short = len(text) < 30
295
- has_caps = any(c.isupper() for c in text[1:]) if len(text) > 1 else False # ignore first char
296
- has_exclamation = "!" in text
297
- all_caps_words = sum(1 for w in text.split() if w.isupper() and len(w) > 1)
298
-
299
- # Score
300
- pos_score = len(positive_hits)
301
- neg_score = len(negative_hits)
302
-
303
- # Caps/short boost negative
304
- if all_caps_words >= 2:
305
- neg_score += 2
306
- if is_short and neg_score > 0:
307
- neg_score += 1 # Short + negative = terse frustration
308
-
309
- if urgency_hits:
310
- neg_score += 1 # Urgency often means something is wrong
311
-
312
- # Determine sentiment
313
- if neg_score > pos_score and neg_score >= 1:
314
- sentiment = "negative"
315
- intensity = min(1.0, 0.3 + neg_score * 0.15)
316
- if intensity > 0.7:
317
- guidance = "MODE: Ultra-concise. Zero explanations. Solve and show result."
318
- else:
319
- guidance = "MODE: Concise. Less context, more direct action."
320
- elif pos_score > neg_score and pos_score >= 1:
321
- sentiment = "positive"
322
- intensity = min(1.0, 0.3 + pos_score * 0.15)
323
- guidance = "MODE: Normal. Good time to suggest backlog ideas or improvements."
324
- elif urgency_hits:
325
- sentiment = "urgent"
326
- intensity = 0.8
327
- guidance = "MODE: Immediate action. No preambles."
328
- else:
329
- sentiment = "neutral"
330
- intensity = 0.5
331
- guidance = ""
332
-
333
- return {
334
- "sentiment": sentiment,
335
- "intensity": round(intensity, 2),
336
- "signals": positive_hits + negative_hits + urgency_hits,
337
- "guidance": guidance,
338
- }
339
-
340
-
341
- def log_sentiment(text: str) -> dict:
342
- """Detect and log user's sentiment. Returns the detection result."""
343
- result = detect_sentiment(text)
344
- if result["sentiment"] != "neutral":
345
- db = _get_db()
346
- db.execute(
347
- "INSERT INTO sentiment_log (sentiment, intensity, signals) VALUES (?, ?, ?)",
348
- (result["sentiment"], result["intensity"], ",".join(result["signals"]))
349
- )
350
- db.commit()
351
- return result
352
-
353
-
354
- def get_trust_score() -> float:
355
- """Get current trust score. Starts at 50, range 0-100."""
356
- db = _get_db()
357
- row = db.execute("SELECT score FROM trust_score ORDER BY id DESC LIMIT 1").fetchone()
358
- if row is None:
359
- # Initialize
360
- db.execute(
361
- "INSERT INTO trust_score (score, event, delta, context) VALUES (50, 'init', 0, 'Initial trust score')"
362
- )
363
- db.commit()
364
- return 50.0
365
- return row[0]
366
-
367
-
368
- def _annotate_adaptive_log(event: str, delta: float):
369
- """Retroactively annotate the most recent adaptive_log entry with trust feedback."""
370
- try:
371
- from db import get_db
372
- conn = get_db()
373
- conn.execute(
374
- "UPDATE adaptive_log SET feedback_event = ?, feedback_delta = ?, "
375
- "feedback_ts = datetime('now') "
376
- "WHERE id = (SELECT id FROM adaptive_log "
377
- "WHERE feedback_event IS NULL "
378
- "AND timestamp >= datetime('now', '-5 minutes') "
379
- "ORDER BY id DESC LIMIT 1)",
380
- (event, int(delta))
381
- )
382
- conn.commit()
383
- except Exception:
384
- pass
385
-
386
-
387
- def adjust_trust(event: str, context: str = "", custom_delta: float = None) -> dict:
388
- """Adjust trust score based on an event.
389
-
390
- Args:
391
- event: Event type from TRUST_EVENTS or custom
392
- context: Description of what happened
393
- custom_delta: Override the default point value
394
-
395
- Returns:
396
- Dict with old_score, delta, new_score, event
397
- """
398
- db = _get_db()
399
- old_score = get_trust_score()
400
-
401
- events = get_trust_events()
402
- delta = custom_delta if custom_delta is not None else events.get(event, 0)
403
- if delta == 0 and custom_delta is None:
404
- return {"old_score": old_score, "delta": 0, "new_score": old_score, "event": event, "error": "unknown event"}
405
-
406
- new_score = max(0.0, min(100.0, old_score + delta))
407
-
408
- db.execute(
409
- "INSERT INTO trust_score (score, event, delta, context) VALUES (?, ?, ?, ?)",
410
- (new_score, event, delta, context[:500])
411
- )
412
- db.commit()
413
-
414
- # Annotate adaptive log for learned weights
415
- _annotate_adaptive_log(event, delta)
416
-
417
- # Somatic event logging for repeated_error events (append-only in nexo.db)
418
- if event == "repeated_error" and context:
419
- try:
420
- from db import get_db as get_nexo_db
421
- area = context.split(":")[0].strip() if ":" in context else "unknown"
422
- get_nexo_db().execute(
423
- "INSERT INTO somatic_events (target, target_type, event_type, delta, source) VALUES (?, ?, ?, ?, ?)",
424
- (area, "area", "repeated_error", 0.20, f"trust:{event}")
425
- )
426
- get_nexo_db().commit()
427
- except Exception:
428
- pass
429
-
430
- return {
431
- "old_score": round(old_score, 1),
432
- "delta": delta,
433
- "new_score": round(new_score, 1),
434
- "event": event,
435
- }
436
-
437
-
438
- def get_trust_history(days: int = 7) -> dict:
439
- """Get trust score history and sentiment summary."""
440
- db = _get_db()
441
- cutoff = (datetime.utcnow() - timedelta(days=days)).isoformat()
442
-
443
- # Trust events
444
- events = db.execute(
445
- "SELECT event, delta, score, context, created_at FROM trust_score WHERE created_at >= ? ORDER BY id",
446
- (cutoff,)
447
- ).fetchall()
448
-
449
- # Sentiment distribution
450
- sentiments = db.execute(
451
- "SELECT sentiment, COUNT(*) as cnt, AVG(intensity) as avg_int FROM sentiment_log WHERE created_at >= ? GROUP BY sentiment",
452
- (cutoff,)
453
- ).fetchall()
454
-
455
- current = get_trust_score()
456
- start_score = events[0]["score"] - events[0]["delta"] if events else current
457
-
458
- return {
459
- "current_score": round(current, 1),
460
- "period_start_score": round(start_score, 1),
461
- "net_change": round(current - start_score, 1),
462
- "events": [{"event": e["event"], "delta": e["delta"], "score": round(e["score"], 1), "context": e["context"][:100], "at": e["created_at"]} for e in events],
463
- "sentiment_distribution": {s["sentiment"]: {"count": s["cnt"], "avg_intensity": round(s["avg_int"], 2)} for s in sentiments},
464
- }
@@ -1,106 +0,0 @@
1
- {
2
- "$schema": "NEXO cron manifest — synced by nexo_update to LaunchAgents (macOS) or systemd timers (Linux)",
3
- "version": 2,
4
- "crons": [
5
- {
6
- "id": "deep-sleep",
7
- "script": "scripts/nexo-deep-sleep.sh",
8
- "type": "shell",
9
- "schedule": {"hour": 4, "minute": 30},
10
- "description": "Overnight session analysis — 4 phases: collect, extract, synthesize, apply",
11
- "core": true
12
- },
13
- {
14
- "id": "sleep",
15
- "script": "scripts/nexo-sleep.py",
16
- "schedule": {"hour": 4, "minute": 0},
17
- "description": "Nightly memory consolidation and dream cycle",
18
- "core": true
19
- },
20
- {
21
- "id": "cognitive-decay",
22
- "script": "scripts/nexo-cognitive-decay.py",
23
- "schedule": {"hour": 3, "minute": 0},
24
- "description": "Memory decay — reduce strength of unaccessed memories",
25
- "core": true
26
- },
27
- {
28
- "id": "learning-housekeep",
29
- "script": "scripts/nexo-learning-housekeep.py",
30
- "schedule": {"hour": 3, "minute": 15},
31
- "description": "Archive stale learnings, deduplicate, validate",
32
- "core": true
33
- },
34
- {
35
- "id": "immune",
36
- "script": "scripts/nexo-immune.py",
37
- "interval_seconds": 1800,
38
- "description": "Health monitor — checks MCP, DB, services, auto-repairs",
39
- "core": true
40
- },
41
- {
42
- "id": "watchdog",
43
- "script": "scripts/nexo-watchdog.sh",
44
- "type": "shell",
45
- "interval_seconds": 1800,
46
- "description": "System health checks — snapshots, logs, alerts",
47
- "core": true
48
- },
49
- {
50
- "id": "self-audit",
51
- "script": "scripts/nexo-daily-self-audit.py",
52
- "schedule": {"hour": 7, "minute": 0},
53
- "description": "Daily self-audit — validates learnings, protocols, drift",
54
- "core": true
55
- },
56
- {
57
- "id": "postmortem",
58
- "script": "scripts/nexo-postmortem-consolidator.py",
59
- "schedule": {"hour": 23, "minute": 30},
60
- "description": "Consolidate session post-mortems into patterns",
61
- "core": true
62
- },
63
- {
64
- "id": "evolution",
65
- "script": "scripts/nexo-evolution-run.py",
66
- "schedule": {"hour": 5, "minute": 0, "weekday": 0},
67
- "description": "Weekly self-improvement cycle — propose and evaluate changes",
68
- "core": true
69
- },
70
- {
71
- "id": "followup-hygiene",
72
- "script": "scripts/nexo-followup-hygiene.py",
73
- "schedule": {"hour": 5, "minute": 0},
74
- "description": "Clean stale followups, archive completed, validate dates",
75
- "core": true
76
- },
77
- {
78
- "id": "synthesis",
79
- "script": "scripts/nexo-synthesis.py",
80
- "interval_seconds": 7200,
81
- "description": "Periodic synthesis — cross-reference learnings, decisions, changes",
82
- "core": true
83
- },
84
- {
85
- "id": "auto-close-sessions",
86
- "script": "scripts/nexo-auto-close-sessions.py",
87
- "interval_seconds": 300,
88
- "description": "Close stale sessions that lost their parent process",
89
- "core": true
90
- },
91
- {
92
- "id": "github-monitor",
93
- "script": "scripts/nexo-github-monitor.py",
94
- "schedule": {"hour": 8, "minute": 0},
95
- "description": "Monitor GitHub repo — issues, PRs, stars, auto-respond",
96
- "core": true
97
- },
98
- {
99
- "id": "catchup",
100
- "script": "scripts/nexo-catchup.py",
101
- "schedule": {"hour": 8, "minute": 30},
102
- "description": "Morning catchup briefing for the user",
103
- "core": true
104
- }
105
- ]
106
- }