nexo-brain 2.3.0 → 2.3.2

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 (299) hide show
  1. package/README.md +1 -1
  2. package/bin/nexo-brain.js +92 -9
  3. package/bin/postinstall.js +22 -15
  4. package/package.json +7 -4
  5. package/src/auto_update.py +194 -5
  6. package/src/crons/sync.py +6 -2
  7. package/src/db/_core.py +1 -0
  8. package/src/db/_entities.py +1 -0
  9. package/src/db/_episodic.py +1 -0
  10. package/src/db/_learnings.py +1 -0
  11. package/src/db/_reminders.py +1 -0
  12. package/src/db/_schema.py +11 -1
  13. package/src/db/_sessions.py +1 -0
  14. package/src/db/_skills.py +1 -0
  15. package/src/hooks/capture-tool-logs.sh +23 -6
  16. package/src/hooks/session-start.sh +4 -3
  17. package/src/plugin_loader.py +1 -0
  18. package/src/plugins/update.py +377 -26
  19. package/src/scripts/deep-sleep/apply_findings.py +1 -0
  20. package/src/scripts/deep-sleep/collect.py +1 -0
  21. package/src/scripts/deep-sleep/extract.py +1 -0
  22. package/src/scripts/deep-sleep/synthesize.py +1 -0
  23. package/src/scripts/nexo-catchup.py +29 -4
  24. package/src/scripts/nexo-daily-self-audit.py +21 -1
  25. package/src/scripts/nexo-evolution-run.py +21 -1
  26. package/src/scripts/nexo-learning-housekeep.py +1 -0
  27. package/src/scripts/nexo-postmortem-consolidator.py +34 -9
  28. package/src/scripts/nexo-sleep.py +32 -10
  29. package/src/scripts/nexo-synthesis.py +29 -9
  30. package/src/scripts/nexo-update.sh +109 -7
  31. package/src/scripts/nexo-watchdog.sh +122 -58
  32. package/src/server.py +66 -1
  33. package/src/tools_coordination.py +1 -0
  34. package/src/tools_sessions.py +1 -0
  35. package/scripts/migrate-to-unified 2.sh +0 -813
  36. package/scripts/migrate-to-unified.sh +0 -813
  37. package/scripts/migrate-v1.5-to-v1.6 2.py +0 -778
  38. package/scripts/migrate-v1.5-to-v1.6.py +0 -778
  39. package/scripts/migrate-v1.7-to-v1.8 2.py +0 -214
  40. package/scripts/migrate-v1.7-to-v1.8.py +0 -214
  41. package/scripts/nexo-preflight.sh +0 -236
  42. package/scripts/pre-commit-check 2.sh +0 -55
  43. package/scripts/pre-commit-check.sh +0 -55
  44. package/src/__pycache__/auto_close_sessions.cpython-314.pyc +0 -0
  45. package/src/__pycache__/auto_update.cpython-310.pyc +0 -0
  46. package/src/__pycache__/hnsw_index.cpython-310.pyc +0 -0
  47. package/src/__pycache__/hnsw_index.cpython-314.pyc +0 -0
  48. package/src/__pycache__/kg_populate.cpython-310.pyc +0 -0
  49. package/src/__pycache__/knowledge_graph.cpython-310.pyc +0 -0
  50. package/src/__pycache__/plugin_loader.cpython-310.pyc +0 -0
  51. package/src/__pycache__/plugin_loader.cpython-314.pyc +0 -0
  52. package/src/__pycache__/tools_coordination.cpython-310.pyc +0 -0
  53. package/src/__pycache__/tools_credentials.cpython-310.pyc +0 -0
  54. package/src/__pycache__/tools_learnings.cpython-310.pyc +0 -0
  55. package/src/__pycache__/tools_menu.cpython-310.pyc +0 -0
  56. package/src/__pycache__/tools_reminders.cpython-310.pyc +0 -0
  57. package/src/__pycache__/tools_reminders_crud.cpython-310.pyc +0 -0
  58. package/src/__pycache__/tools_sessions.cpython-310.pyc +0 -0
  59. package/src/__pycache__/tools_task_history.cpython-310.pyc +0 -0
  60. package/src/auto_close_sessions 2.py +0 -159
  61. package/src/auto_update 2.py +0 -634
  62. package/src/claim_graph 2.py +0 -323
  63. package/src/cognitive/__init__ 2.py +0 -62
  64. package/src/cognitive/__pycache__/__init__.cpython-310.pyc +0 -0
  65. package/src/cognitive/__pycache__/__init__.cpython-312.pyc +0 -0
  66. package/src/cognitive/__pycache__/__init__.cpython-314.pyc +0 -0
  67. package/src/cognitive/__pycache__/_core.cpython-310.pyc +0 -0
  68. package/src/cognitive/__pycache__/_core.cpython-312.pyc +0 -0
  69. package/src/cognitive/__pycache__/_core.cpython-314.pyc +0 -0
  70. package/src/cognitive/__pycache__/_decay.cpython-310.pyc +0 -0
  71. package/src/cognitive/__pycache__/_decay.cpython-312.pyc +0 -0
  72. package/src/cognitive/__pycache__/_decay.cpython-314.pyc +0 -0
  73. package/src/cognitive/__pycache__/_ingest.cpython-310.pyc +0 -0
  74. package/src/cognitive/__pycache__/_ingest.cpython-312.pyc +0 -0
  75. package/src/cognitive/__pycache__/_ingest.cpython-314.pyc +0 -0
  76. package/src/cognitive/__pycache__/_memory.cpython-310.pyc +0 -0
  77. package/src/cognitive/__pycache__/_memory.cpython-312.pyc +0 -0
  78. package/src/cognitive/__pycache__/_memory.cpython-314.pyc +0 -0
  79. package/src/cognitive/__pycache__/_search.cpython-310.pyc +0 -0
  80. package/src/cognitive/__pycache__/_search.cpython-312.pyc +0 -0
  81. package/src/cognitive/__pycache__/_search.cpython-314.pyc +0 -0
  82. package/src/cognitive/__pycache__/_trust.cpython-310.pyc +0 -0
  83. package/src/cognitive/__pycache__/_trust.cpython-312.pyc +0 -0
  84. package/src/cognitive/__pycache__/_trust.cpython-314.pyc +0 -0
  85. package/src/cognitive/_core 2.py +0 -567
  86. package/src/cognitive/_decay 2.py +0 -382
  87. package/src/cognitive/_ingest 2.py +0 -892
  88. package/src/cognitive/_memory 2.py +0 -912
  89. package/src/cognitive/_search 2.py +0 -949
  90. package/src/cognitive/_trust 2.py +0 -464
  91. package/src/crons/__pycache__/sync.cpython-314.pyc +0 -0
  92. package/src/crons/manifest 2.json +0 -106
  93. package/src/crons/sync 2.py +0 -217
  94. package/src/dashboard/__init__ 2.py +0 -0
  95. package/src/dashboard/__pycache__/__init__.cpython-310.pyc +0 -0
  96. package/src/dashboard/__pycache__/app.cpython-310.pyc +0 -0
  97. package/src/dashboard/app 2.py +0 -789
  98. package/src/db/__init__ 2.py +0 -89
  99. package/src/db/__pycache__/__init__.cpython-310.pyc +0 -0
  100. package/src/db/__pycache__/__init__.cpython-312.pyc +0 -0
  101. package/src/db/__pycache__/__init__.cpython-314.pyc +0 -0
  102. package/src/db/__pycache__/_core.cpython-310.pyc +0 -0
  103. package/src/db/__pycache__/_core.cpython-312.pyc +0 -0
  104. package/src/db/__pycache__/_core.cpython-314.pyc +0 -0
  105. package/src/db/__pycache__/_credentials.cpython-310.pyc +0 -0
  106. package/src/db/__pycache__/_credentials.cpython-312.pyc +0 -0
  107. package/src/db/__pycache__/_credentials.cpython-314.pyc +0 -0
  108. package/src/db/__pycache__/_cron_runs.cpython-310.pyc +0 -0
  109. package/src/db/__pycache__/_cron_runs.cpython-314.pyc +0 -0
  110. package/src/db/__pycache__/_entities.cpython-310.pyc +0 -0
  111. package/src/db/__pycache__/_entities.cpython-312.pyc +0 -0
  112. package/src/db/__pycache__/_entities.cpython-314.pyc +0 -0
  113. package/src/db/__pycache__/_episodic.cpython-310.pyc +0 -0
  114. package/src/db/__pycache__/_episodic.cpython-312.pyc +0 -0
  115. package/src/db/__pycache__/_episodic.cpython-314.pyc +0 -0
  116. package/src/db/__pycache__/_evolution.cpython-310.pyc +0 -0
  117. package/src/db/__pycache__/_evolution.cpython-312.pyc +0 -0
  118. package/src/db/__pycache__/_evolution.cpython-314.pyc +0 -0
  119. package/src/db/__pycache__/_fts.cpython-310.pyc +0 -0
  120. package/src/db/__pycache__/_fts.cpython-312.pyc +0 -0
  121. package/src/db/__pycache__/_fts.cpython-314.pyc +0 -0
  122. package/src/db/__pycache__/_learnings.cpython-310.pyc +0 -0
  123. package/src/db/__pycache__/_learnings.cpython-312.pyc +0 -0
  124. package/src/db/__pycache__/_learnings.cpython-314.pyc +0 -0
  125. package/src/db/__pycache__/_reminders.cpython-310.pyc +0 -0
  126. package/src/db/__pycache__/_reminders.cpython-312.pyc +0 -0
  127. package/src/db/__pycache__/_reminders.cpython-314.pyc +0 -0
  128. package/src/db/__pycache__/_schema.cpython-310.pyc +0 -0
  129. package/src/db/__pycache__/_schema.cpython-312.pyc +0 -0
  130. package/src/db/__pycache__/_schema.cpython-314.pyc +0 -0
  131. package/src/db/__pycache__/_sessions.cpython-310.pyc +0 -0
  132. package/src/db/__pycache__/_sessions.cpython-312.pyc +0 -0
  133. package/src/db/__pycache__/_sessions.cpython-314.pyc +0 -0
  134. package/src/db/__pycache__/_skills.cpython-310.pyc +0 -0
  135. package/src/db/__pycache__/_skills.cpython-312.pyc +0 -0
  136. package/src/db/__pycache__/_skills.cpython-314.pyc +0 -0
  137. package/src/db/__pycache__/_tasks.cpython-310.pyc +0 -0
  138. package/src/db/__pycache__/_tasks.cpython-312.pyc +0 -0
  139. package/src/db/__pycache__/_tasks.cpython-314.pyc +0 -0
  140. package/src/db/_core 2.py +0 -417
  141. package/src/db/_credentials 2.py +0 -124
  142. package/src/db/_entities 2.py +0 -178
  143. package/src/db/_episodic 2.py +0 -738
  144. package/src/db/_evolution 2.py +0 -54
  145. package/src/db/_fts 2.py +0 -406
  146. package/src/db/_learnings 2.py +0 -168
  147. package/src/db/_reminders 2.py +0 -338
  148. package/src/db/_schema 2.py +0 -364
  149. package/src/db/_sessions 2.py +0 -300
  150. package/src/db/_tasks 2.py +0 -91
  151. package/src/evolution_cycle 2.py +0 -266
  152. package/src/hnsw_index 2.py +0 -254
  153. package/src/hooks/auto_capture 2.py +0 -208
  154. package/src/hooks/caffeinate-guard 2.sh +0 -8
  155. package/src/hooks/capture-session 2.sh +0 -21
  156. package/src/hooks/capture-tool-logs 2.sh +0 -127
  157. package/src/hooks/daily-briefing-check 2.sh +0 -33
  158. package/src/hooks/inbox-hook 2.sh +0 -76
  159. package/src/hooks/post-compact 2.sh +0 -148
  160. package/src/hooks/pre-compact 2.sh +0 -151
  161. package/src/hooks/session-start 2.sh +0 -268
  162. package/src/hooks/session-stop 2.sh +0 -140
  163. package/src/kg_populate 2.py +0 -290
  164. package/src/knowledge_graph 2.py +0 -257
  165. package/src/maintenance 2.py +0 -59
  166. package/src/migrate_embeddings 2.py +0 -122
  167. package/src/plugin_loader 2.py +0 -202
  168. package/src/plugins/__init__ 2.py +0 -0
  169. package/src/plugins/__pycache__/__init__ 2.cpython-310.pyc +0 -0
  170. package/src/plugins/__pycache__/__init__.cpython-310.pyc +0 -0
  171. package/src/plugins/__pycache__/__init__.cpython-314.pyc +0 -0
  172. package/src/plugins/__pycache__/adaptive_mode 2.cpython-310.pyc +0 -0
  173. package/src/plugins/__pycache__/adaptive_mode.cpython-310.pyc +0 -0
  174. package/src/plugins/__pycache__/adaptive_mode.cpython-314.pyc +0 -0
  175. package/src/plugins/__pycache__/agents 2.cpython-310.pyc +0 -0
  176. package/src/plugins/__pycache__/agents.cpython-310.pyc +0 -0
  177. package/src/plugins/__pycache__/artifact_registry 2.cpython-310.pyc +0 -0
  178. package/src/plugins/__pycache__/artifact_registry.cpython-310.pyc +0 -0
  179. package/src/plugins/__pycache__/backup 2.cpython-310.pyc +0 -0
  180. package/src/plugins/__pycache__/backup.cpython-310.pyc +0 -0
  181. package/src/plugins/__pycache__/cognitive_memory 2.cpython-310.pyc +0 -0
  182. package/src/plugins/__pycache__/cognitive_memory.cpython-310.pyc +0 -0
  183. package/src/plugins/__pycache__/core_rules 2.cpython-310.pyc +0 -0
  184. package/src/plugins/__pycache__/core_rules.cpython-310.pyc +0 -0
  185. package/src/plugins/__pycache__/cortex 2.cpython-310.pyc +0 -0
  186. package/src/plugins/__pycache__/cortex.cpython-310.pyc +0 -0
  187. package/src/plugins/__pycache__/entities 2.cpython-310.pyc +0 -0
  188. package/src/plugins/__pycache__/entities.cpython-310.pyc +0 -0
  189. package/src/plugins/__pycache__/episodic_memory 2.cpython-310.pyc +0 -0
  190. package/src/plugins/__pycache__/episodic_memory.cpython-310.pyc +0 -0
  191. package/src/plugins/__pycache__/evolution 2.cpython-310.pyc +0 -0
  192. package/src/plugins/__pycache__/evolution.cpython-310.pyc +0 -0
  193. package/src/plugins/__pycache__/guard 2.cpython-310.pyc +0 -0
  194. package/src/plugins/__pycache__/guard.cpython-310.pyc +0 -0
  195. package/src/plugins/__pycache__/knowledge_graph_tools 2.cpython-310.pyc +0 -0
  196. package/src/plugins/__pycache__/knowledge_graph_tools.cpython-310.pyc +0 -0
  197. package/src/plugins/__pycache__/preferences 2.cpython-310.pyc +0 -0
  198. package/src/plugins/__pycache__/preferences.cpython-310.pyc +0 -0
  199. package/src/plugins/__pycache__/schedule.cpython-310.pyc +0 -0
  200. package/src/plugins/__pycache__/schedule.cpython-314.pyc +0 -0
  201. package/src/plugins/__pycache__/skills.cpython-310.pyc +0 -0
  202. package/src/plugins/__pycache__/skills.cpython-314.pyc +0 -0
  203. package/src/plugins/__pycache__/update 2.cpython-310.pyc +0 -0
  204. package/src/plugins/__pycache__/update.cpython-310.pyc +0 -0
  205. package/src/plugins/adaptive_mode 2.py +0 -805
  206. package/src/plugins/agents 2.py +0 -52
  207. package/src/plugins/artifact_registry 2.py +0 -450
  208. package/src/plugins/backup 2.py +0 -104
  209. package/src/plugins/cognitive_memory 2.py +0 -564
  210. package/src/plugins/core_rules 2.py +0 -252
  211. package/src/plugins/cortex 2.py +0 -299
  212. package/src/plugins/entities 2.py +0 -67
  213. package/src/plugins/episodic_memory 2.py +0 -533
  214. package/src/plugins/evolution 2.py +0 -115
  215. package/src/plugins/guard 2.py +0 -746
  216. package/src/plugins/knowledge_graph_tools 2.py +0 -105
  217. package/src/plugins/preferences 2.py +0 -47
  218. package/src/plugins/update 2.py +0 -256
  219. package/src/requirements 2.txt +0 -12
  220. package/src/rules/__init__ 2.py +0 -0
  221. package/src/rules/core-rules 2.json +0 -331
  222. package/src/rules/migrate 2.py +0 -207
  223. package/src/scripts/__pycache__/nexo-auto-update.cpython-314.pyc +0 -0
  224. package/src/scripts/__pycache__/nexo-catchup.cpython-314.pyc +0 -0
  225. package/src/scripts/__pycache__/nexo-cognitive-decay.cpython-314.pyc +0 -0
  226. package/src/scripts/__pycache__/nexo-daily-self-audit.cpython-314.pyc +0 -0
  227. package/src/scripts/__pycache__/nexo-evolution-run.cpython-314.pyc +0 -0
  228. package/src/scripts/__pycache__/nexo-followup-hygiene.cpython-314.pyc +0 -0
  229. package/src/scripts/__pycache__/nexo-immune.cpython-314.pyc +0 -0
  230. package/src/scripts/__pycache__/nexo-install.cpython-314.pyc +0 -0
  231. package/src/scripts/__pycache__/nexo-learning-housekeep.cpython-314.pyc +0 -0
  232. package/src/scripts/__pycache__/nexo-learning-validator.cpython-314.pyc +0 -0
  233. package/src/scripts/__pycache__/nexo-migrate.cpython-314.pyc +0 -0
  234. package/src/scripts/__pycache__/nexo-postmortem-consolidator.cpython-314.pyc +0 -0
  235. package/src/scripts/__pycache__/nexo-pre-commit.cpython-314.pyc +0 -0
  236. package/src/scripts/__pycache__/nexo-proactive-dashboard.cpython-314.pyc +0 -0
  237. package/src/scripts/__pycache__/nexo-reflection.cpython-314.pyc +0 -0
  238. package/src/scripts/__pycache__/nexo-runtime-preflight.cpython-314.pyc +0 -0
  239. package/src/scripts/__pycache__/nexo-send-email.cpython-314.pyc +0 -0
  240. package/src/scripts/__pycache__/nexo-send-reply.cpython-314.pyc +0 -0
  241. package/src/scripts/__pycache__/nexo-sleep.cpython-314.pyc +0 -0
  242. package/src/scripts/__pycache__/nexo-synthesis.cpython-314.pyc +0 -0
  243. package/src/scripts/__pycache__/nexo-watchdog-smoke.cpython-314.pyc +0 -0
  244. package/src/scripts/check-context 2.py +0 -264
  245. package/src/scripts/nexo-auto-update 2.py +0 -6
  246. package/src/scripts/nexo-backup 2.sh +0 -25
  247. package/src/scripts/nexo-brain-activation 2.sh +0 -140
  248. package/src/scripts/nexo-catchup 2.py +0 -242
  249. package/src/scripts/nexo-cognitive-decay 2.py +0 -182
  250. package/src/scripts/nexo-daily-self-audit 2.py +0 -552
  251. package/src/scripts/nexo-deep-sleep 2.sh +0 -97
  252. package/src/scripts/nexo-evolution-run 2.py +0 -597
  253. package/src/scripts/nexo-followup-hygiene 2.py +0 -112
  254. package/src/scripts/nexo-github-monitor 2.py +0 -256
  255. package/src/scripts/nexo-immune 2.py +0 -927
  256. package/src/scripts/nexo-inbox-hook 2.sh +0 -74
  257. package/src/scripts/nexo-install 2.py +0 -6
  258. package/src/scripts/nexo-learning-housekeep 2.py +0 -245
  259. package/src/scripts/nexo-learning-validator 2.py +0 -207
  260. package/src/scripts/nexo-migrate 2.py +0 -232
  261. package/src/scripts/nexo-postmortem-consolidator 2.py +0 -421
  262. package/src/scripts/nexo-pre-commit 2.py +0 -120
  263. package/src/scripts/nexo-prevent-sleep 2.sh +0 -29
  264. package/src/scripts/nexo-proactive-dashboard 2.py +0 -345
  265. package/src/scripts/nexo-reflection 2.py +0 -253
  266. package/src/scripts/nexo-runtime-preflight 2.py +0 -274
  267. package/src/scripts/nexo-send-email 2.py +0 -25
  268. package/src/scripts/nexo-send-email.py +0 -25
  269. package/src/scripts/nexo-send-reply 2.py +0 -178
  270. package/src/scripts/nexo-send-reply.py +0 -178
  271. package/src/scripts/nexo-sleep 2.py +0 -592
  272. package/src/scripts/nexo-snapshot-restore 2.sh +0 -35
  273. package/src/scripts/nexo-synthesis 2.py +0 -253
  274. package/src/scripts/nexo-tcc-approve 2.sh +0 -79
  275. package/src/scripts/nexo-update 2.sh +0 -161
  276. package/src/scripts/nexo-watchdog 2.sh +0 -878
  277. package/src/scripts/nexo-watchdog-smoke 2.py +0 -119
  278. package/src/server 2.py +0 -733
  279. package/src/storage_router 2.py +0 -32
  280. package/src/tools_coordination 2.py +0 -102
  281. package/src/tools_credentials 2.py +0 -68
  282. package/src/tools_learnings 2.py +0 -220
  283. package/src/tools_menu 2.py +0 -227
  284. package/src/tools_reminders 2.py +0 -86
  285. package/src/tools_reminders_crud 2.py +0 -159
  286. package/src/tools_sessions 2.py +0 -476
  287. package/src/tools_task_history 2.py +0 -57
  288. package/templates/CLAUDE.md 2.template +0 -63
  289. package/templates/openclaw 2.json +0 -13
  290. package/tests/__init__ 2.py +0 -0
  291. package/tests/__init__.py +0 -0
  292. package/tests/conftest 2.py +0 -71
  293. package/tests/conftest.py +0 -71
  294. package/tests/test_cognitive 2.py +0 -205
  295. package/tests/test_cognitive.py +0 -205
  296. package/tests/test_knowledge_graph 2.py +0 -140
  297. package/tests/test_knowledge_graph.py +0 -140
  298. package/tests/test_migrations 2.py +0 -137
  299. package/tests/test_migrations.py +0 -137
@@ -1,564 +0,0 @@
1
- """Cognitive Memory plugin — RAG retrieval over NEXO's Atkinson-Shiffrin memory stores."""
2
-
3
- import sys
4
- import os
5
-
6
- # Ensure site-packages is in path for numpy/fastembed
7
- _site = "/opt/homebrew/lib/python{}.{}/site-packages".format(sys.version_info.major, sys.version_info.minor)
8
- if os.path.isdir(_site) and _site not in sys.path:
9
- sys.path.insert(0, _site)
10
-
11
- import cognitive
12
-
13
-
14
- def handle_cognitive_retrieve(
15
- query: str,
16
- top_k: int = 10,
17
- min_score: float = 0.5,
18
- stores: str = "both",
19
- source_type: str = "",
20
- domain: str = "",
21
- include_archived: bool = False,
22
- use_hyde: bool = False,
23
- spreading_depth: int = 0,
24
- ) -> str:
25
- """RAG query over cognitive memory (STM + LTM). Triggers rehearsal on retrieved memories.
26
-
27
- Args:
28
- query: Natural language query to search for
29
- top_k: Maximum number of results to return (default 10)
30
- min_score: Minimum cosine similarity score (default 0.5)
31
- stores: Which store to search — "both", "stm", or "ltm" (default "both")
32
- source_type: Filter by source type e.g. "change", "learning", "diary" (default: all)
33
- domain: Filter by domain e.g. "project-a", "shopify" (default: all)
34
- include_archived: If True, also search archived memories (default False)
35
- use_hyde: If True, use HyDE query expansion — embeds 3-5 query variants and searches with centroid. Better recall for conceptual queries. (default False)
36
- spreading_depth: If >0, boost co-activated neighbors (memories frequently retrieved together). 1=direct neighbors only. (default 0)
37
- """
38
- if not query or not query.strip():
39
- return "ERROR: query is required."
40
-
41
- results = cognitive.search(
42
- query_text=query,
43
- top_k=top_k,
44
- min_score=min_score,
45
- stores=stores,
46
- exclude_dormant=True,
47
- rehearse=True,
48
- source_type_filter=source_type,
49
- include_archived=include_archived,
50
- use_hyde=use_hyde,
51
- spreading_depth=spreading_depth,
52
- )
53
-
54
- # Apply domain filter post-search (cognitive.search doesn't filter by domain natively)
55
- if domain:
56
- results = [r for r in results if r.get("domain", "") == domain]
57
-
58
- formatted = cognitive.format_results(results)
59
- mode_parts = [f"stores={stores}", f"min_score={min_score}"]
60
- if use_hyde:
61
- mode_parts.append("hyde=ON")
62
- if spreading_depth > 0:
63
- mode_parts.append(f"spreading={spreading_depth}")
64
- header = f"COGNITIVE RETRIEVE — query: '{query}' | {len(results)} results ({', '.join(mode_parts)})\n\n"
65
- return header + formatted
66
-
67
-
68
- def handle_cognitive_stats() -> str:
69
- """Return cognitive memory system metrics: STM/LTM counts, strengths, retrieval stats, top domains."""
70
- stats = cognitive.get_stats()
71
-
72
- lines = [
73
- "COGNITIVE MEMORY STATS",
74
- f" STM active: {stats['stm_active']} (+ {stats.get('stm_promoted', 0)} promoted to LTM, {stats.get('stm_total', 0)} total)",
75
- f" LTM active: {stats['ltm_active']}",
76
- f" LTM dormant: {stats['ltm_dormant']}",
77
- f" Avg STM strength: {stats['avg_stm_strength']:.3f}",
78
- f" Avg LTM strength: {stats['avg_ltm_strength']:.3f}",
79
- f" Total retrievals: {stats['total_retrievals']}",
80
- f" Avg retrieval score: {stats['avg_retrieval_score']:.3f}",
81
- ]
82
-
83
- if stats["top_domains_stm"]:
84
- lines.append(" Top STM domains:")
85
- for domain, cnt in stats["top_domains_stm"]:
86
- lines.append(f" {domain}: {cnt}")
87
-
88
- if stats["top_domains_ltm"]:
89
- lines.append(" Top LTM domains:")
90
- for domain, cnt in stats["top_domains_ltm"]:
91
- lines.append(f" {domain}: {cnt}")
92
-
93
- if "quarantine" in stats:
94
- q = stats["quarantine"]
95
- lines.append(f" Quarantine pending: {q.get('pending', 0)}")
96
- lines.append(f" Quarantine promoted: {q.get('promoted', 0)}")
97
- lines.append(f" Quarantine rejected: {q.get('rejected', 0)}")
98
- lines.append(f" Quarantine expired: {q.get('expired', 0)}")
99
-
100
- if "prediction_error_gate" in stats:
101
- g = stats["prediction_error_gate"]
102
- lines.append(" PE Gate (session):")
103
- lines.append(f" Accepted (novel): {g['accepted_novel']}")
104
- lines.append(f" Accepted (refine): {g['accepted_refinement']}")
105
- lines.append(f" Rejected (redundant): {g['rejected']}")
106
- lines.append(f" Rejection rate: {g['rejection_rate_pct']}%")
107
-
108
- return "\n".join(lines)
109
-
110
-
111
- def handle_cognitive_inspect(memory_id: int, store: str = "ltm") -> str:
112
- """Inspect a specific memory by ID without triggering rehearsal.
113
-
114
- Args:
115
- memory_id: Integer ID of the memory to inspect
116
- store: Which store to read from — "stm" or "ltm" (default "ltm")
117
- """
118
- if store not in ("stm", "ltm"):
119
- return "ERROR: store must be 'stm' or 'ltm'."
120
-
121
- db = cognitive._get_db()
122
- table = "stm_memories" if store == "stm" else "ltm_memories"
123
-
124
- row = db.execute(f"SELECT * FROM {table} WHERE id = ?", (memory_id,)).fetchone()
125
- if row is None:
126
- return f"ERROR: Memory #{memory_id} not found in {store.upper()}."
127
-
128
- content_preview = row["content"][:500]
129
- if len(row["content"]) > 500:
130
- content_preview += "..."
131
-
132
- lines = [
133
- f"COGNITIVE INSPECT — {store.upper()} #{memory_id}",
134
- f" source_type: {row['source_type']}",
135
- f" source_id: {row['source_id']}",
136
- f" source_title: {row['source_title']}",
137
- f" domain: {row['domain']}",
138
- f" strength: {row['strength']:.4f}",
139
- f" access_count: {row['access_count']}",
140
- f" created_at: {row['created_at']}",
141
- f" last_accessed: {row['last_accessed']}",
142
- ]
143
-
144
- # Lifecycle state
145
- lifecycle = row["lifecycle_state"] or "active"
146
- lines.append(f" lifecycle: {lifecycle}")
147
- if row["snooze_until"]:
148
- lines.append(f" snooze_until: {row['snooze_until']}")
149
-
150
- if store == "ltm":
151
- dormant_label = "YES" if row["is_dormant"] else "no"
152
- lines.append(f" dormant: {dormant_label}")
153
- if row["tags"]:
154
- lines.append(f" tags: {row['tags']}")
155
-
156
- if store == "stm":
157
- promoted_label = "YES" if row["promoted_to_ltm"] else "no"
158
- lines.append(f" promoted: {promoted_label}")
159
-
160
- lines.append(f" content:\n {content_preview}")
161
-
162
- return "\n".join(lines)
163
-
164
-
165
- def handle_cognitive_metrics(days: int = 7) -> str:
166
- """Cognitive memory performance metrics (spec section 9).
167
-
168
- Returns retrieval relevance %, repeat error rate, score distribution,
169
- and whether multilingual model switch is recommended.
170
-
171
- Args:
172
- days: Period to analyze in days (default 7)
173
- """
174
- metrics = cognitive.get_metrics(days=days)
175
- repeats = cognitive.check_repeat_errors()
176
-
177
- lines = [
178
- f"COGNITIVE METRICS — last {days} days",
179
- "",
180
- "Retrieval Performance:",
181
- f" Total retrievals: {metrics['total_retrievals']}",
182
- f" Retrievals/day: {metrics['retrievals_per_day']}",
183
- f" Relevance (>=0.6): {metrics['retrieval_relevance_pct']}% (target: >60%)",
184
- f" Avg top score: {metrics['avg_top_score']}",
185
- "",
186
- "Score Distribution:",
187
- f" >0.8 (excellent): {metrics['score_distribution']['above_80']}",
188
- f" 0.7-0.8 (good): {metrics['score_distribution']['70_80']}",
189
- f" 0.6-0.7 (ok): {metrics['score_distribution']['60_70']}",
190
- f" 0.5-0.6 (weak): {metrics['score_distribution']['50_60']}",
191
- f" <0.5 (irrelevant): {metrics['score_distribution']['below_50']}",
192
- "",
193
- "Repeat Error Rate:",
194
- f" New learnings (7d): {repeats['new_count']}",
195
- f" Duplicates found: {repeats['duplicate_count']}",
196
- f" Repeat rate: {repeats['repeat_rate_pct']}% (target: <10%)",
197
- ]
198
-
199
- if metrics["needs_multilingual"]:
200
- lines.append("")
201
- lines.append("⚠ RECOMMENDATION: Switch to multilingual model (intfloat/multilingual-e5-small)")
202
- lines.append(f" Reason: relevance {metrics['retrieval_relevance_pct']}% < 70% with {metrics['total_retrievals']}+ retrievals")
203
-
204
- if repeats["duplicates"]:
205
- lines.append("")
206
- lines.append("Top duplicates:")
207
- for d in repeats["duplicates"][:5]:
208
- lines.append(f" [{d['score']}] STM#{d['new_stm_id']}: {d['new_content'][:60]}...")
209
- lines.append(f" ≈ LTM#{d['ltm_id']}: {d['ltm_content'][:60]}...")
210
-
211
- # Prediction Error Gate stats
212
- gate = cognitive.get_gate_stats()
213
- if gate["total_evaluated"] > 0:
214
- lines.append("")
215
- lines.append("Prediction Error Gate (session):")
216
- lines.append(f" Novel accepted: {gate['accepted_novel']}")
217
- lines.append(f" Refinements: {gate['accepted_refinement']}")
218
- lines.append(f" Rejected redundant: {gate['rejected']}")
219
- lines.append(f" Rejection rate: {gate['rejection_rate_pct']}%")
220
-
221
- return "\n".join(lines)
222
-
223
-
224
- def handle_cognitive_sentiment(text: str) -> str:
225
- """Detect user's sentiment from his text. Returns mood, intensity, and guidance.
226
-
227
- Call this with user's recent message to adapt NEXO's tone and behavior.
228
- Also logs the sentiment for historical tracking.
229
-
230
- Args:
231
- text: user's recent message or instruction
232
- """
233
- result = cognitive.log_sentiment(text)
234
- trust = cognitive.get_trust_score()
235
-
236
- lines = [
237
- f"SENTIMENT: {result['sentiment'].upper()} (intensity: {result['intensity']})",
238
- f"Trust Score: {trust:.0f}/100",
239
- ]
240
- if result["signals"]:
241
- lines.append(f"Signals: {', '.join(result['signals'])}")
242
- if result["guidance"]:
243
- lines.append(f"Guidance: {result['guidance']}")
244
-
245
- return "\n".join(lines)
246
-
247
-
248
- def handle_cognitive_trust(event: str = '', context: str = '', delta: float = None) -> str:
249
- """View or adjust the trust score (alignment index 0-100).
250
-
251
- Without arguments: shows current score and recent history.
252
- With event: adjusts score based on event type.
253
-
254
- Args:
255
- event: Event type — explicit_thanks, delegation, paradigm_shift, sibling_detected,
256
- proactive_action, correction, repeated_error, override, correction_fatigue,
257
- forgot_followup. Or empty to just view.
258
- context: Description of what happened
259
- delta: Custom point value (overrides default for the event type)
260
- """
261
- if not event:
262
- # View mode
263
- trust = cognitive.get_trust_score()
264
- history = cognitive.get_trust_history(days=7)
265
-
266
- lines = [
267
- f"TRUST SCORE: {trust:.0f}/100",
268
- f"7-day change: {history['net_change']:+.0f} (from {history['period_start_score']:.0f})",
269
- "",
270
- ]
271
-
272
- if history["sentiment_distribution"]:
273
- lines.append("Sentiment (7d):")
274
- for sent, data in history["sentiment_distribution"].items():
275
- lines.append(f" {sent}: {data['count']}x (avg intensity {data['avg_intensity']})")
276
- lines.append("")
277
-
278
- if history["events"]:
279
- lines.append("Recent events:")
280
- for e in history["events"][-10:]:
281
- lines.append(f" [{e['delta']:+.0f}] {e['event']}: {e['context'][:60]} ({e['at'][:16]})")
282
-
283
- return "\n".join(lines)
284
-
285
- # Adjust mode
286
- result = cognitive.adjust_trust(event, context, delta)
287
- if "error" in result:
288
- valid = ", ".join(sorted(cognitive.TRUST_EVENTS.keys()))
289
- return f"Unknown event '{event}'. Valid: {valid}"
290
-
291
- return f"Trust: {result['old_score']:.0f} → {result['new_score']:.0f} ({result['delta']:+.0f}) [{event}]"
292
-
293
-
294
- def handle_cognitive_dissonance(instruction: str, force: bool = False) -> str:
295
- """Detect cognitive dissonance: find established memories that conflict with a new instruction.
296
-
297
- Use BEFORE applying a new preference or rule from user that might contradict
298
- existing knowledge. If conflicts found, verbalize them and ask user to resolve.
299
-
300
- Args:
301
- instruction: The new instruction or preference to check against LTM
302
- force: If True, skip discussion — execute instruction, auto-resolve all conflicts as
303
- 'exception', and flag for review in the nocturnal process (23:30).
304
- """
305
- conflicts = cognitive.detect_dissonance(instruction)
306
- if not conflicts:
307
- return f"No dissonance detected. Instruction '{instruction[:80]}' is consistent with existing LTM."
308
-
309
- if force:
310
- # Auto-resolve all as exceptions, log for nocturnal review
311
- for c in conflicts:
312
- cognitive.resolve_dissonance(
313
- c["memory_id"], "exception",
314
- f"[FORCE] {instruction[:200]} — auto-exception, pending nocturnal review"
315
- )
316
- return (f"FORCE: {len(conflicts)} conflicts auto-resolved as exceptions. "
317
- f"Instruction executed. Flagged for review at 23:30.")
318
-
319
- lines = [
320
- f"COGNITIVE DISSONANCE DETECTED — {len(conflicts)} conflicting memories:",
321
- f"New instruction: \"{instruction[:200]}\"",
322
- "",
323
- ]
324
- for c in conflicts:
325
- lines.append(f" LTM #{c['memory_id']} [{c['source_type']}] (strength={c['strength']:.2f}, {c['access_count']} accesses)")
326
- lines.append(f" Similarity: {c['similarity']}")
327
- lines.append(f" Content: {c['content'][:200]}")
328
- lines.append("")
329
-
330
- lines.append("RESOLVE with nexo_cognitive_resolve, or use force=True to skip:")
331
- lines.append(" - 'paradigm_shift': user changed his mind permanently.")
332
- lines.append(" - 'exception': One-time override. Old memory stays.")
333
- lines.append(" - 'override': Old memory was wrong.")
334
-
335
- return "\n".join(lines)
336
-
337
-
338
- def handle_cognitive_resolve(memory_id: int, resolution: str, context: str = '') -> str:
339
- """Resolve a cognitive dissonance by applying user's decision.
340
-
341
- Args:
342
- memory_id: The LTM memory ID from the dissonance detection
343
- resolution: 'paradigm_shift' (permanent change), 'exception' (one-time), or 'override' (old was wrong)
344
- context: Optional context about why this resolution was chosen
345
- """
346
- return cognitive.resolve_dissonance(memory_id, resolution, context)
347
-
348
-
349
- def handle_cognitive_pin(memory_id: int, store: str = "auto") -> str:
350
- """Pin a memory so it NEVER decays and gets boosted in search results (+0.2 similarity).
351
-
352
- Args:
353
- memory_id: Integer ID of the memory to pin
354
- store: Which store — "stm", "ltm", or "auto" (tries both, default "auto")
355
- """
356
- return cognitive.set_lifecycle(memory_id, "pinned", store)
357
-
358
-
359
- def handle_cognitive_snooze(memory_id: int, until_date: str, store: str = "auto") -> str:
360
- """Snooze a memory — hidden from searches until the given date, then auto-restores to active.
361
-
362
- Args:
363
- memory_id: Integer ID of the memory to snooze
364
- until_date: Date to restore the memory (YYYY-MM-DD format)
365
- store: Which store — "stm", "ltm", or "auto" (tries both, default "auto")
366
- """
367
- return cognitive.set_lifecycle(memory_id, "snoozed", store, snooze_until=until_date)
368
-
369
-
370
- def handle_cognitive_archive(memory_id: int, store: str = "auto") -> str:
371
- """Archive a memory — stored but excluded from normal searches. Can be restored later.
372
-
373
- Args:
374
- memory_id: Integer ID of the memory to archive
375
- store: Which store — "stm", "ltm", or "auto" (tries both, default "auto")
376
- """
377
- return cognitive.set_lifecycle(memory_id, "archived", store)
378
-
379
-
380
- def handle_cognitive_restore(memory_id: int, store: str = "auto") -> str:
381
- """Restore a memory to active state (from pinned, snoozed, or archived).
382
-
383
- Args:
384
- memory_id: Integer ID of the memory to restore
385
- store: Which store — "stm", "ltm", or "auto" (tries both, default "auto")
386
- """
387
- return cognitive.set_lifecycle(memory_id, "active", store)
388
-
389
-
390
- def handle_cognitive_quarantine_list(status: str = "pending", limit: int = 20) -> str:
391
- """List quarantine queue items. Shows memories awaiting promotion to STM.
392
-
393
- Args:
394
- status: Filter — 'pending', 'promoted', 'rejected', 'expired', or 'all' (default 'pending')
395
- limit: Max items to return (default 20)
396
- """
397
- items = cognitive.quarantine_list(status=status, limit=limit)
398
- stats = cognitive.quarantine_stats()
399
-
400
- lines = [
401
- f"QUARANTINE QUEUE — {stats['pending']} pending | {stats['promoted']} promoted | {stats['rejected']} rejected | {stats['expired']} expired",
402
- f"Showing: {status} (limit {limit})",
403
- "",
404
- ]
405
-
406
- if not items:
407
- lines.append("No items found.")
408
- else:
409
- for item in items:
410
- lines.append(f" #{item['id']} [{item['status']}] source={item['source']} type={item['source_type']} domain={item['domain'] or '-'}")
411
- lines.append(f" confidence={item['confidence']:.1f} checks={item['promotion_checks']} created={item['created_at'][:16]}")
412
- if item['promoted_at']:
413
- lines.append(f" promoted_at={item['promoted_at'][:16]}")
414
- lines.append(f" {item['content']}")
415
- lines.append("")
416
-
417
- return "\n".join(lines)
418
-
419
-
420
- def handle_cognitive_quarantine_promote(quarantine_id: int) -> str:
421
- """Manually promote a quarantine item to STM, bypassing the automatic promotion policy.
422
-
423
- Args:
424
- quarantine_id: ID of the quarantine entry to promote
425
- """
426
- return cognitive.quarantine_promote(quarantine_id)
427
-
428
-
429
- def handle_cognitive_quarantine_reject(quarantine_id: int, reason: str = "") -> str:
430
- """Manually reject a quarantine item.
431
-
432
- Args:
433
- quarantine_id: ID of the quarantine entry to reject
434
- reason: Optional reason for rejection
435
- """
436
- return cognitive.quarantine_reject(quarantine_id, reason)
437
-
438
-
439
- def handle_cognitive_quarantine_process() -> str:
440
- """Run the quarantine promotion cycle. Evaluates all pending items against the promotion policy.
441
-
442
- Promotion rules:
443
- - source='user_direct' → already promoted at ingest
444
- - source='inferred' + second occurrence found → promote
445
- - source='agent_observation' + >24h old + no LTM contradiction → promote
446
- - Contradicts LTM (cosine >0.8) → reject
447
- - >7 days old → expire
448
- """
449
- result = cognitive.process_quarantine()
450
- lines = [
451
- "QUARANTINE PROCESSING COMPLETE",
452
- f" Promoted: {result['promoted']}",
453
- f" Rejected: {result['rejected']}",
454
- f" Expired: {result['expired']}",
455
- f" Still pending: {result['still_pending']}",
456
- f" Total: {result['total_processed']}",
457
- ]
458
- return "\n".join(lines)
459
-
460
-
461
- # ============================================================================
462
- # Prospective Memory trigger handlers (Feature 3)
463
- # ============================================================================
464
-
465
- def handle_cognitive_trigger_create(pattern: str, action: str, context: str = "") -> str:
466
- """Create a prospective memory trigger — fires when text matches pattern.
467
-
468
- Args:
469
- pattern: Keywords to match (case-insensitive, comma-separated for OR matching)
470
- action: What to do / remind about when the trigger fires
471
- context: Optional context about why this trigger was created
472
- """
473
- trigger_id = cognitive.create_trigger(pattern, action, context)
474
- return f"Trigger #{trigger_id} created — armed. Pattern: '{pattern}' | Action: '{action}'"
475
-
476
-
477
- def handle_cognitive_trigger_list(status: str = "armed") -> str:
478
- """List prospective memory triggers.
479
-
480
- Args:
481
- status: Filter — 'armed' (active, waiting), 'fired' (already triggered), 'all'
482
- """
483
- triggers = cognitive.list_triggers(status)
484
- if not triggers:
485
- return f"No {status} triggers found."
486
-
487
- lines = [f"PROSPECTIVE TRIGGERS ({status}) — {len(triggers)} total", ""]
488
- for t in triggers:
489
- status_icon = "+" if t["status"] == "armed" else "x"
490
- lines.append(f" [{status_icon}] #{t['id']} pattern='{t['trigger_pattern']}'")
491
- lines.append(f" action: {t['action']}")
492
- if t.get("context"):
493
- lines.append(f" context: {t['context']}")
494
- lines.append(f" created: {t['created_at'][:16]}")
495
- if t.get("fired_at"):
496
- lines.append(f" fired: {t['fired_at'][:16]}")
497
- lines.append("")
498
-
499
- return "\n".join(lines)
500
-
501
-
502
- def handle_cognitive_trigger_check(text: str, use_semantic: bool = False) -> str:
503
- """Check text against all armed triggers and fire matching ones.
504
-
505
- Args:
506
- text: Text to check against triggers (e.g. user message, heartbeat context)
507
- use_semantic: Also use embedding similarity (slower but catches conceptual matches)
508
- """
509
- fired = cognitive.check_triggers(text, use_semantic=use_semantic)
510
- if not fired:
511
- return "No triggers fired."
512
-
513
- lines = [f"TRIGGERS FIRED: {len(fired)}", ""]
514
- for t in fired:
515
- lines.append(f" #{t['id']} [{t['match_type']}] pattern='{t['pattern']}'")
516
- lines.append(f" ACTION: {t['action']}")
517
- if t.get("context"):
518
- lines.append(f" context: {t['context']}")
519
- lines.append("")
520
-
521
- return "\n".join(lines)
522
-
523
-
524
- def handle_cognitive_trigger_delete(trigger_id: int) -> str:
525
- """Delete a prospective memory trigger.
526
-
527
- Args:
528
- trigger_id: ID of the trigger to delete
529
- """
530
- return cognitive.delete_trigger(trigger_id)
531
-
532
-
533
- def handle_cognitive_trigger_rearm(trigger_id: int) -> str:
534
- """Re-arm a fired trigger so it can fire again.
535
-
536
- Args:
537
- trigger_id: ID of the trigger to re-arm
538
- """
539
- return cognitive.rearm_trigger(trigger_id)
540
-
541
-
542
- TOOLS = [
543
- (handle_cognitive_retrieve, "nexo_cognitive_retrieve", "RAG query over cognitive memory (STM+LTM). Triggers rehearsal on retrieved results."),
544
- (handle_cognitive_stats, "nexo_cognitive_stats", "Cognitive memory system metrics: STM/LTM counts, strengths, retrieval stats, quarantine counts"),
545
- (handle_cognitive_inspect, "nexo_cognitive_inspect", "Inspect a specific memory by ID (debug). Does NOT trigger rehearsal."),
546
- (handle_cognitive_metrics, "nexo_cognitive_metrics", "Performance metrics: retrieval relevance %, repeat error rate, multilingual recommendation (spec section 9)"),
547
- (handle_cognitive_dissonance, "nexo_cognitive_dissonance", "Detect conflicts between a new instruction and established LTM memories. force=True to skip discussion."),
548
- (handle_cognitive_resolve, "nexo_cognitive_resolve", "Resolve a cognitive dissonance: paradigm_shift, exception, or override."),
549
- (handle_cognitive_sentiment, "nexo_cognitive_sentiment", "Detect user's sentiment and get tone guidance. Also logs for tracking."),
550
- (handle_cognitive_trust, "nexo_cognitive_trust", "View or adjust trust score (0-100). Without args: view. With event: adjust."),
551
- (handle_cognitive_pin, "nexo_cognitive_pin", "Pin a memory — never decays, boosted +0.2 in search results."),
552
- (handle_cognitive_snooze, "nexo_cognitive_snooze", "Snooze a memory — hidden from searches until a date, then auto-restores."),
553
- (handle_cognitive_archive, "nexo_cognitive_archive", "Archive a memory — excluded from searches, can be restored."),
554
- (handle_cognitive_restore, "nexo_cognitive_restore", "Restore a memory to active state (from pinned/snoozed/archived)."),
555
- (handle_cognitive_quarantine_list, "nexo_cognitive_quarantine_list", "List quarantine queue items awaiting promotion to STM."),
556
- (handle_cognitive_quarantine_promote, "nexo_cognitive_quarantine_promote", "Manually promote a quarantine item to STM."),
557
- (handle_cognitive_quarantine_reject, "nexo_cognitive_quarantine_reject", "Manually reject a quarantine item."),
558
- (handle_cognitive_quarantine_process, "nexo_cognitive_quarantine_process", "Run quarantine promotion cycle — evaluate pending items against policy."),
559
- (handle_cognitive_trigger_create, "nexo_cognitive_trigger_create", "Create a prospective memory trigger — 'when X is mentioned, remind about Y'."),
560
- (handle_cognitive_trigger_list, "nexo_cognitive_trigger_list", "List prospective triggers by status (armed/fired/all)."),
561
- (handle_cognitive_trigger_check, "nexo_cognitive_trigger_check", "Check text against armed triggers. Returns fired triggers with actions."),
562
- (handle_cognitive_trigger_delete, "nexo_cognitive_trigger_delete", "Delete a prospective trigger by ID."),
563
- (handle_cognitive_trigger_rearm, "nexo_cognitive_trigger_rearm", "Re-arm a fired trigger so it can fire again."),
564
- ]