nexo-brain 5.3.26 → 5.3.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.
Files changed (211) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/package.json +1 -1
  3. package/src/server.py +3 -0
  4. package/src/tools_sessions.py +6 -1
  5. package/src/dashboard/static/favicon 2.svg +0 -32
  6. package/src/dashboard/static/nexo-logo 2.png +0 -0
  7. package/src/dashboard/static/nexo-logo 2.svg +0 -40
  8. package/src/dashboard/static/style 2.css +0 -2458
  9. package/src/dashboard/templates/adaptive 2.html +0 -118
  10. package/src/dashboard/templates/artifacts 2.html +0 -133
  11. package/src/dashboard/templates/backups 2.html +0 -136
  12. package/src/dashboard/templates/base 2.html +0 -417
  13. package/src/dashboard/templates/calendar 2.html +0 -591
  14. package/src/dashboard/templates/chat 2.html +0 -356
  15. package/src/dashboard/templates/claims 2.html +0 -259
  16. package/src/dashboard/templates/cortex 2.html +0 -321
  17. package/src/dashboard/templates/credentials 2.html +0 -128
  18. package/src/dashboard/templates/crons 2.html +0 -370
  19. package/src/dashboard/templates/dashboard 2.html +0 -494
  20. package/src/dashboard/templates/dreams 2.html +0 -252
  21. package/src/dashboard/templates/email 2.html +0 -160
  22. package/src/dashboard/templates/evolution 2.html +0 -189
  23. package/src/dashboard/templates/feed 2.html +0 -249
  24. package/src/dashboard/templates/followup_health 2.html +0 -170
  25. package/src/dashboard/templates/graph 2.html +0 -201
  26. package/src/dashboard/templates/guard 2.html +0 -259
  27. package/src/dashboard/templates/inbox 2.html +0 -251
  28. package/src/dashboard/templates/memory 2.html +0 -420
  29. package/src/dashboard/templates/operations 2.html +0 -608
  30. package/src/dashboard/templates/plugins 2.html +0 -185
  31. package/src/dashboard/templates/protocol 2.html +0 -199
  32. package/src/dashboard/templates/rules 2.html +0 -246
  33. package/src/dashboard/templates/sentiment 2.html +0 -247
  34. package/src/dashboard/templates/sessions 2.html +0 -218
  35. package/src/dashboard/templates/skills 2.html +0 -329
  36. package/src/dashboard/templates/somatic 2.html +0 -73
  37. package/src/dashboard/templates/triggers 2.html +0 -133
  38. package/src/dashboard/templates/trust 2.html +0 -360
  39. package/src/db/__init__ 2.py +0 -259
  40. package/src/db/_core 2.py +0 -437
  41. package/src/db/_credentials 2.py +0 -124
  42. package/src/db/_episodic 2.py +0 -762
  43. package/src/db/_evolution 2.py +0 -54
  44. package/src/db/_fts 2.py +0 -406
  45. package/src/db/_goal_profiles 2.py +0 -376
  46. package/src/db/_hot_context 2.py +0 -660
  47. package/src/db/_outcomes 2.py +0 -800
  48. package/src/db/_personal_scripts 2.py +0 -582
  49. package/src/db/_sessions 2.py +0 -330
  50. package/src/db/_tasks 2.py +0 -91
  51. package/src/db/_watchers 2.py +0 -173
  52. package/src/doctor/formatters 2.py +0 -52
  53. package/src/doctor/models 2.py +0 -69
  54. package/src/doctor/planes 2.py +0 -87
  55. package/src/doctor/providers/__init__ 2.py +0 -1
  56. package/src/doctor/providers/deep 2.py +0 -367
  57. package/src/evolution_cycle 2.py +0 -519
  58. package/src/hooks/auto_capture 2.py +0 -208
  59. package/src/hooks/caffeinate-guard 2.sh +0 -8
  60. package/src/hooks/capture-session 2.sh +0 -21
  61. package/src/hooks/capture-tool-logs 2.sh +0 -158
  62. package/src/hooks/daily-briefing-check 2.sh +0 -33
  63. package/src/hooks/heartbeat-enforcement 2.py +0 -90
  64. package/src/hooks/heartbeat-posttool 2.sh +0 -18
  65. package/src/hooks/inbox-hook 2.sh +0 -76
  66. package/src/hooks/post-compact 2.sh +0 -152
  67. package/src/hooks/pre-compact 2.sh +0 -169
  68. package/src/hooks/protocol-guardrail 2.sh +0 -10
  69. package/src/hooks/protocol-pretool-guardrail 2.sh +0 -9
  70. package/src/hooks/session-stop 2.sh +0 -52
  71. package/src/kg_populate 2.py +0 -292
  72. package/src/maintenance 2.py +0 -53
  73. package/src/memory_backends 2.py +0 -71
  74. package/src/migrate_embeddings 2.py +0 -124
  75. package/src/nexo_sdk 2.py +0 -103
  76. package/src/observability 2.py +0 -199
  77. package/src/plugin_loader 2.py +0 -217
  78. package/src/plugins/__init__ 2.py +0 -0
  79. package/src/plugins/artifact_registry 2.py +0 -450
  80. package/src/plugins/backup 2.py +0 -127
  81. package/src/plugins/claims_tools 2.py +0 -119
  82. package/src/plugins/cognitive_memory 2.py +0 -609
  83. package/src/plugins/core_rules 2.py +0 -252
  84. package/src/plugins/cortex 2.py +0 -1155
  85. package/src/plugins/entities 2.py +0 -67
  86. package/src/plugins/episodic_memory 2.py +0 -560
  87. package/src/plugins/evolution 2.py +0 -167
  88. package/src/plugins/goal_engine 2.py +0 -142
  89. package/src/plugins/guard 2.py +0 -862
  90. package/src/plugins/impact 2.py +0 -29
  91. package/src/plugins/knowledge_graph_tools 2.py +0 -137
  92. package/src/plugins/media_memory_tools 2.py +0 -98
  93. package/src/plugins/memory_export 2.py +0 -196
  94. package/src/plugins/outcomes 2.py +0 -130
  95. package/src/plugins/personal_scripts 2.py +0 -117
  96. package/src/plugins/preferences 2.py +0 -47
  97. package/src/plugins/protocol 2.py +0 -1449
  98. package/src/plugins/simple_api 2.py +0 -106
  99. package/src/plugins/skills 2.py +0 -341
  100. package/src/plugins/state_watchers 2.py +0 -79
  101. package/src/plugins/update 2.py +0 -986
  102. package/src/plugins/user_state_tools 2.py +0 -43
  103. package/src/plugins/workflow 2.py +0 -588
  104. package/src/protocol_settings 2.py +0 -59
  105. package/src/public_contribution 2.py +0 -466
  106. package/src/public_evolution_queue 2.py +0 -241
  107. package/src/requirements 2.txt +0 -14
  108. package/src/retroactive_learnings 2.py +0 -373
  109. package/src/rules/__init__ 2.py +0 -0
  110. package/src/rules/core-rules 2.json +0 -331
  111. package/src/rules/migrate 2.py +0 -207
  112. package/src/runtime_power 2.py +0 -874
  113. package/src/script_registry 2.py +0 -1559
  114. package/src/scripts/check-context 2.py +0 -272
  115. package/src/scripts/deep-sleep/apply_findings 2.py +0 -2327
  116. package/src/scripts/deep-sleep/collect 2.py +0 -928
  117. package/src/scripts/deep-sleep/extract 2.py +0 -330
  118. package/src/scripts/deep-sleep/extract-prompt 2.md +0 -285
  119. package/src/scripts/deep-sleep/synthesize 2.py +0 -312
  120. package/src/scripts/deep-sleep/synthesize-prompt 2.md +0 -336
  121. package/src/scripts/nexo-agent-run 2.py +0 -75
  122. package/src/scripts/nexo-auto-update 2.py +0 -6
  123. package/src/scripts/nexo-backup 2.sh +0 -25
  124. package/src/scripts/nexo-brain-activation 2.sh +0 -140
  125. package/src/scripts/nexo-catchup 2.py +0 -300
  126. package/src/scripts/nexo-cognitive-decay 2.py +0 -257
  127. package/src/scripts/nexo-cortex-cycle 2.py +0 -293
  128. package/src/scripts/nexo-cron-wrapper 2.sh +0 -53
  129. package/src/scripts/nexo-daily-self-audit 2.py +0 -2161
  130. package/src/scripts/nexo-dashboard 2.sh +0 -29
  131. package/src/scripts/nexo-deep-sleep 2.sh +0 -86
  132. package/src/scripts/nexo-evolution-run 2.py +0 -1664
  133. package/src/scripts/nexo-followup-hygiene 2.py +0 -139
  134. package/src/scripts/nexo-hook-record 2.py +0 -42
  135. package/src/scripts/nexo-immune 2.py +0 -936
  136. package/src/scripts/nexo-impact-scorer 2.py +0 -117
  137. package/src/scripts/nexo-inbox-hook 2.sh +0 -74
  138. package/src/scripts/nexo-install 2.py +0 -6
  139. package/src/scripts/nexo-learning-housekeep 2.py +0 -401
  140. package/src/scripts/nexo-learning-validator 2.py +0 -266
  141. package/src/scripts/nexo-migrate 2.py +0 -260
  142. package/src/scripts/nexo-outcome-checker 2.py +0 -127
  143. package/src/scripts/nexo-postmortem-consolidator 2.py +0 -456
  144. package/src/scripts/nexo-pre-commit 2.py +0 -120
  145. package/src/scripts/nexo-prevent-sleep 2.sh +0 -35
  146. package/src/scripts/nexo-proactive-dashboard 2.py +0 -354
  147. package/src/scripts/nexo-reflection 2.py +0 -256
  148. package/src/scripts/nexo-runtime-preflight 2.py +0 -274
  149. package/src/scripts/nexo-sleep 2.py +0 -631
  150. package/src/scripts/nexo-snapshot-restore 2.sh +0 -35
  151. package/src/scripts/nexo-sync-clients 2.py +0 -16
  152. package/src/scripts/nexo-synthesis 2.py +0 -475
  153. package/src/scripts/nexo-tcc-approve 2.sh +0 -79
  154. package/src/scripts/nexo-update 2.sh +0 -306
  155. package/src/scripts/nexo-watchdog 2.sh +0 -1207
  156. package/src/scripts/nexo-watchdog-smoke 2.py +0 -119
  157. package/src/scripts/rehydrate_learnings_from_archive 2.py +0 -245
  158. package/src/server 2.py +0 -1296
  159. package/src/skills/run-nexo-audit-phase/guide 2.md +0 -43
  160. package/src/skills/run-nexo-audit-phase/skill 2.json +0 -59
  161. package/src/skills/run-nexo-core-fix-cycle/guide 2.md +0 -17
  162. package/src/skills/run-nexo-core-fix-cycle/script 2.py +0 -276
  163. package/src/skills/run-nexo-core-fix-cycle/skill 2.json +0 -58
  164. package/src/skills/run-release-final-audit/guide 2.md +0 -16
  165. package/src/skills/run-release-final-audit/script 2.py +0 -259
  166. package/src/skills/run-release-final-audit/skill 2.json +0 -77
  167. package/src/skills/run-runtime-doctor/guide 2.md +0 -12
  168. package/src/skills/run-runtime-doctor/script 2.py +0 -21
  169. package/src/skills/run-runtime-doctor/skill 2.json +0 -25
  170. package/src/skills_runtime 2.py +0 -932
  171. package/src/state_watchers_runtime 2.py +0 -475
  172. package/src/storage_router 2.py +0 -32
  173. package/src/system_catalog 2.py +0 -786
  174. package/src/tools_coordination 2.py +0 -103
  175. package/src/tools_credentials 2.py +0 -68
  176. package/src/tools_drive 2.py +0 -487
  177. package/src/tools_hot_context 2.py +0 -163
  178. package/src/tools_learnings 2.py +0 -612
  179. package/src/tools_menu 2.py +0 -229
  180. package/src/tools_reminders 2.py +0 -88
  181. package/src/tools_reminders_crud 2.py +0 -363
  182. package/src/tools_sessions 2.py +0 -1054
  183. package/src/tools_system_catalog 2.py +0 -19
  184. package/src/tools_task_history 2.py +0 -57
  185. package/src/tools_transcripts 2.py +0 -98
  186. package/src/transcript_utils 2.py +0 -412
  187. package/src/user_context 2.py +0 -46
  188. package/src/user_data_portability 2.py +0 -328
  189. package/src/user_state_model 2.py +0 -170
  190. package/templates/CLAUDE.md 2.template +0 -108
  191. package/templates/CODEX.AGENTS.md 2.template +0 -66
  192. package/templates/launchagents/README 2.md +0 -132
  193. package/templates/launchagents/com.nexo.auto-close-sessions 2.plist +0 -39
  194. package/templates/launchagents/com.nexo.catchup 2.plist +0 -39
  195. package/templates/launchagents/com.nexo.cognitive-decay 2.plist +0 -40
  196. package/templates/launchagents/com.nexo.dashboard 2.plist +0 -43
  197. package/templates/launchagents/com.nexo.deep-sleep 2.plist +0 -43
  198. package/templates/launchagents/com.nexo.evolution 2.plist +0 -44
  199. package/templates/launchagents/com.nexo.followup-hygiene 2.plist +0 -45
  200. package/templates/launchagents/com.nexo.immune 2.plist +0 -41
  201. package/templates/launchagents/com.nexo.postmortem 2.plist +0 -45
  202. package/templates/launchagents/com.nexo.self-audit 2.plist +0 -47
  203. package/templates/launchagents/com.nexo.synthesis 2.plist +0 -45
  204. package/templates/launchagents/com.nexo.watchdog 2.plist +0 -37
  205. package/templates/nexo_helper 2.py +0 -301
  206. package/templates/openclaw 2.json +0 -13
  207. package/templates/plugin-template 2.py +0 -40
  208. package/templates/script-template 2.py +0 -59
  209. package/templates/script-template 2.sh +0 -13
  210. package/templates/skill-script-template 2.py +0 -48
  211. package/templates/skill-template 2.md +0 -33
@@ -1,330 +0,0 @@
1
- #!/usr/bin/env python3
2
- from __future__ import annotations
3
- """
4
- Deep Sleep v2 -- Phase 2: Extract findings from each session using the configured automation backend.
5
-
6
- For each session in the context file, sends the extract-prompt.md to Claude
7
- and collects structured findings. Merges all per-session results into
8
- $DATE-extractions.json.
9
-
10
- Environment variables:
11
- NEXO_HOME -- root of the NEXO installation (default: ~/.nexo)
12
- """
13
- import json
14
- import os
15
- import subprocess
16
- import sys
17
- from datetime import datetime
18
- from pathlib import Path
19
-
20
- NEXO_HOME = Path(os.environ.get("NEXO_HOME", str(Path.home() / ".nexo")))
21
- NEXO_CODE = Path(os.environ.get("NEXO_CODE", str(Path(__file__).resolve().parents[2])))
22
- DEEP_SLEEP_DIR = NEXO_HOME / "operations" / "deep-sleep"
23
- PROMPT_FILE = Path(__file__).parent / "extract-prompt.md"
24
-
25
- if str(NEXO_CODE) not in sys.path:
26
- sys.path.insert(0, str(NEXO_CODE))
27
-
28
- from agent_runner import AutomationBackendUnavailableError, run_automation_prompt
29
- try:
30
- from client_preferences import resolve_user_model as _resolve_user_model
31
- _USER_MODEL = _resolve_user_model()
32
- except Exception:
33
- _USER_MODEL = ""
34
-
35
-
36
- # No timeout -- headless automation can take as long as needed
37
- CLAUDE_TIMEOUT = 21600 # 3h safety net (prevents zombie processes)
38
-
39
-
40
- def extract_json_from_response(text: str) -> dict | None:
41
- """Parse JSON from Claude's response, handling markdown fences."""
42
- text = text.strip()
43
-
44
- # Strip markdown code fences if present
45
- if text.startswith("```"):
46
- lines = text.split("\n")
47
- # Remove first line (```json or ```) and last line (```)
48
- end = len(lines)
49
- for i in range(len(lines) - 1, 0, -1):
50
- if lines[i].strip() == "```":
51
- end = i
52
- break
53
- text = "\n".join(lines[1:end]).strip()
54
-
55
- # Find the outermost JSON object
56
- brace_start = text.find("{")
57
- if brace_start < 0:
58
- return None
59
-
60
- # Find matching closing brace
61
- depth = 0
62
- for i in range(brace_start, len(text)):
63
- if text[i] == "{":
64
- depth += 1
65
- elif text[i] == "}":
66
- depth -= 1
67
- if depth == 0:
68
- try:
69
- return json.loads(text[brace_start:i + 1])
70
- except json.JSONDecodeError:
71
- break
72
- return None
73
-
74
-
75
- def _safe_session_slug(session_id: str) -> str:
76
- return (
77
- session_id
78
- .replace(".jsonl", "")
79
- .replace(":", "-")
80
- .replace("/", "-")
81
- )
82
-
83
-
84
- def find_session_file(session_id: str, date_dir: Path, session_txt_map: dict[str, str] | None = None) -> Path | None:
85
- """Find the individual .txt file for a session."""
86
- if session_txt_map:
87
- mapped = session_txt_map.get(session_id)
88
- if mapped:
89
- candidate = date_dir / mapped
90
- if candidate.exists():
91
- return candidate
92
- if date_dir and date_dir.exists():
93
- sid_short = _safe_session_slug(session_id)[:20]
94
- for f in sorted(date_dir.glob("session-*.txt")):
95
- if sid_short in f.name:
96
- return f
97
- return None
98
-
99
-
100
- def analyze_session(
101
- session_id: str,
102
- date_dir: Path,
103
- shared_context_file: Path | None,
104
- session_txt_map: dict[str, str] | None = None,
105
- ) -> dict | None:
106
- """Send a session to the automation backend for extraction analysis.
107
-
108
- The backend reads the small per-session file + shared context file.
109
- Prompt is short — the heavy lifting is in the Read tool calls.
110
- """
111
- session_file = find_session_file(session_id, date_dir, session_txt_map=session_txt_map)
112
- if not session_file:
113
- print(f" No session file found for {session_id}", file=sys.stderr)
114
- return None
115
-
116
- print(f" File: {session_file.name} ({session_file.stat().st_size / 1024:.0f} KB)")
117
-
118
- # Build a short prompt — Claude reads the files itself
119
- shared_ctx_instruction = ""
120
- if shared_context_file and shared_context_file.exists():
121
- shared_ctx_instruction = f"\n\nAlso read the shared context (followups, learnings, DB state) at: {shared_context_file}"
122
-
123
- prompt_template = PROMPT_FILE.read_text()
124
- prompt = prompt_template.replace("{{CONTEXT_FILE}}", str(session_file))
125
- prompt = prompt.replace("{{SESSION_ID}}", session_id)
126
- prompt += shared_ctx_instruction
127
-
128
- try:
129
- JSON_SYSTEM_PROMPT = (
130
- "You are a JSON-only analyst. Your ENTIRE response must be a single valid JSON object. "
131
- "No text before it. No text after it. No markdown fences. No explanations. "
132
- "If you want to summarize, put it inside the JSON fields. Start with { and end with }."
133
- )
134
-
135
- result = run_automation_prompt(
136
- prompt,
137
- model=_USER_MODEL or "opus",
138
- timeout=CLAUDE_TIMEOUT,
139
- output_format="text",
140
- append_system_prompt=JSON_SYSTEM_PROMPT,
141
- allowed_tools="Read,Grep,Bash",
142
- )
143
-
144
- if result.returncode != 0:
145
- print(f" Automation backend error (exit {result.returncode}): {result.stderr[:300]}", file=sys.stderr)
146
- return None
147
-
148
- # Filter out stop hook contamination (e.g. "Post-mortem completo.")
149
- output = "\n".join(
150
- line for line in result.stdout.splitlines()
151
- if not line.strip().startswith("Post-mortem") and line.strip()
152
- )
153
- parsed = extract_json_from_response(output)
154
-
155
- # Fallback: if Claude returned text instead of JSON, ask a short conversion call
156
- if not parsed and len(output.strip()) > 50:
157
- print(f" Got text instead of JSON ({len(output)} chars). Converting...")
158
- convert_prompt = (
159
- f"Convert the following analysis into the exact JSON schema required. "
160
- f"Return ONLY the JSON object, nothing else.\n\n"
161
- f"Analysis:\n{output[:8000]}\n\n"
162
- f"Required schema: session_id, findings[], emotional_timeline[], "
163
- f"abandoned_projects[], skill_candidates[], productivity_score, protocol_summary"
164
- )
165
- convert_result = run_automation_prompt(
166
- convert_prompt,
167
- model=_USER_MODEL or "sonnet",
168
- timeout=120,
169
- output_format="text",
170
- append_system_prompt=JSON_SYSTEM_PROMPT,
171
- )
172
- if convert_result.returncode == 0:
173
- parsed = extract_json_from_response(convert_result.stdout)
174
- if parsed:
175
- print(f" Conversion succeeded")
176
-
177
- if not parsed:
178
- # Save raw output for debugging
179
- debug_file = DEEP_SLEEP_DIR / f"debug-extract-{session_id[:20]}.txt"
180
- debug_file.write_text(result.stdout[:5000])
181
- print(f" Failed to parse JSON. Raw output saved to {debug_file}", file=sys.stderr)
182
- return None
183
-
184
- return parsed
185
-
186
- except AutomationBackendUnavailableError as exc:
187
- print(f" Automation backend unavailable: {exc}", file=sys.stderr)
188
- return None
189
- except subprocess.TimeoutExpired:
190
- print(f" Automation backend timeout ({CLAUDE_TIMEOUT}s)", file=sys.stderr)
191
- return None
192
-
193
-
194
- def main():
195
- target_date = sys.argv[1] if len(sys.argv) > 1 else datetime.now().strftime("%Y-%m-%d")
196
-
197
- context_file = DEEP_SLEEP_DIR / f"{target_date}-context.txt"
198
- meta_file = DEEP_SLEEP_DIR / f"{target_date}-meta.json"
199
- date_dir = DEEP_SLEEP_DIR / target_date
200
-
201
- if not context_file.exists() and not date_dir.exists():
202
- print(f"[extract] No context for {target_date}. Run collect.py first.")
203
- sys.exit(1)
204
-
205
- # Read metadata to get session list
206
- if meta_file.exists():
207
- with open(meta_file) as f:
208
- meta = json.load(f)
209
- session_files = meta.get("session_files", [])
210
- session_txt_map = meta.get("session_txt_map", {})
211
- else:
212
- # Fallback: parse context file for session IDs
213
- print("[extract] No meta file found, scanning context for sessions...")
214
- session_files = []
215
- session_txt_map = {}
216
- if context_file.exists():
217
- for line in context_file.read_text().splitlines():
218
- if line.startswith("SESSION ") and ":" in line:
219
- parts = line.split(":", 1)
220
- if len(parts) == 2:
221
- sid = parts[1].strip()
222
- if sid.endswith(".jsonl"):
223
- session_files.append(sid)
224
-
225
- if not session_files:
226
- print(f"[extract] No sessions to analyze for {target_date}.")
227
- output = {"date": target_date, "sessions_analyzed": 0, "extractions": []}
228
- output_file = DEEP_SLEEP_DIR / f"{target_date}-extractions.json"
229
- with open(output_file, "w") as f:
230
- json.dump(output, f, indent=2, ensure_ascii=False)
231
- print(f"[extract] Output: {output_file}")
232
- return
233
-
234
- # Shared context file (followups, learnings, DB state)
235
- shared_context_file = date_dir / "shared-context.txt" if date_dir.exists() else None
236
- if shared_context_file and shared_context_file.exists():
237
- print(f"[extract] Shared context: {shared_context_file} ({shared_context_file.stat().st_size / 1024:.0f} KB)")
238
- else:
239
- shared_context_file = None
240
- print("[extract] No shared context file")
241
-
242
- print(f"[extract] Phase 2: Analyzing {len(session_files)} sessions for {target_date}")
243
- print("[extract] Automation backend: schedule-configured")
244
-
245
- # Checkpoint directory: one JSON per session, survives crashes
246
- checkpoint_dir = date_dir / "checkpoints"
247
- checkpoint_dir.mkdir(parents=True, exist_ok=True)
248
-
249
- all_extractions = []
250
- total_findings = 0
251
- skipped = 0
252
- MAX_RETRIES = 3
253
-
254
- for i, session_id in enumerate(session_files):
255
- sid_safe = _safe_session_slug(session_id)[:40]
256
- checkpoint_file = checkpoint_dir / f"{sid_safe}.json"
257
-
258
- # Resume: skip already-processed sessions
259
- if checkpoint_file.exists():
260
- try:
261
- with open(checkpoint_file) as f:
262
- cached = json.load(f)
263
- findings_count = len(cached.get("findings", []))
264
- total_findings += findings_count
265
- all_extractions.append(cached)
266
- skipped += 1
267
- print(f"[extract] Session {i + 1}/{len(session_files)}: {session_id} (cached, {findings_count} findings)")
268
- continue
269
- except (json.JSONDecodeError, KeyError):
270
- pass # Corrupted checkpoint, re-process
271
-
272
- print(f"[extract] Session {i + 1}/{len(session_files)}: {session_id}")
273
-
274
- # Retry loop
275
- result = None
276
- for attempt in range(1, MAX_RETRIES + 1):
277
- result = analyze_session(
278
- session_id,
279
- date_dir,
280
- shared_context_file,
281
- session_txt_map=session_txt_map,
282
- )
283
- if result:
284
- break
285
- if attempt < MAX_RETRIES:
286
- print(f" -> Attempt {attempt}/{MAX_RETRIES} failed, retrying...")
287
-
288
- if result:
289
- findings_count = len(result.get("findings", []))
290
- total_findings += findings_count
291
- all_extractions.append(result)
292
- # Save checkpoint
293
- with open(checkpoint_file, "w") as f:
294
- json.dump(result, f, indent=2, ensure_ascii=False)
295
- print(f" -> {findings_count} findings extracted (checkpointed)")
296
- else:
297
- print(f" -> Failed after {MAX_RETRIES} attempts, marking as failed")
298
- failed_entry = {
299
- "session_id": session_id,
300
- "findings": [],
301
- "error": f"Extraction failed after {MAX_RETRIES} attempts"
302
- }
303
- all_extractions.append(failed_entry)
304
- # Save failed checkpoint too (so we don't retry forever)
305
- with open(checkpoint_file, "w") as f:
306
- json.dump(failed_entry, f, indent=2, ensure_ascii=False)
307
-
308
- # Merge into output
309
- output = {
310
- "date": target_date,
311
- "sessions_analyzed": len(session_files),
312
- "sessions_succeeded": len([e for e in all_extractions if "error" not in e]),
313
- "sessions_cached": skipped,
314
- "total_findings": total_findings,
315
- "extractions": all_extractions
316
- }
317
-
318
- output_file = DEEP_SLEEP_DIR / f"{target_date}-extractions.json"
319
- with open(output_file, "w") as f:
320
- json.dump(output, f, indent=2, ensure_ascii=False)
321
-
322
- if skipped:
323
- print(f"\n[extract] Done. {total_findings} findings from {len(session_files)} sessions ({skipped} cached, {len(session_files) - skipped} new).")
324
- else:
325
- print(f"\n[extract] Done. {total_findings} findings from {len(session_files)} sessions.")
326
- print(f"[extract] Output: {output_file}")
327
-
328
-
329
- if __name__ == "__main__":
330
- main()
@@ -1,285 +0,0 @@
1
- # Deep Sleep v2 -- Phase 2: Session Extraction
2
-
3
- You are an overnight analyst for an AI agent's cognitive memory system. You have access to the complete transcript of a session between a user and their AI agent.
4
-
5
- ## Setup
6
-
7
- FIRST: Call `nexo_startup` with `task='deep-sleep extraction'` to initialize the system.
8
-
9
- ## Your Task
10
-
11
- Read the context file provided below. It contains:
12
- - The full session transcript (user messages, agent responses, tool usage)
13
- - Active followups, learnings, trust history, and other system state
14
-
15
- For the given session, extract the following categories of findings.
16
-
17
- ### 1. Uncaptured Corrections
18
- The user corrected the agent but no learning was saved.
19
- Signals: frustration tone, repeating instructions 2+ times, explicit corrections ("no", "wrong", "that's not it"), the user having to explain something twice.
20
- For each, note whether it was already captured as a learning (check if `nexo_learning_add` was called after the correction).
21
-
22
- ### 2. Self-Corrected Errors
23
- The agent searched in the wrong place, used the wrong approach, then found the right answer.
24
- These represent knowledge gaps that should become learnings so the agent goes to the right place next time.
25
- Example: agent looked for config in `/etc/` but it was in `~/.config/`.
26
-
27
- ### 3. Unformalised Ideas
28
- The user mentioned an idea, plan, or intention that was never formalized into a followup or reminder.
29
- Signals: "we should...", "it would be nice...", "we could...", "I want to...", future-tense plans without deadlines.
30
-
31
- ### 4. Missed Commitments
32
- The user or agent said "tomorrow", "next week", "when I have time", "I'll look at it later" -- but no followup was created.
33
- Check the tool usage log: was `nexo_followup_create` or `nexo_reminder_create` called after the commitment?
34
-
35
- ### 5. Protocol Compliance
36
- Check whether the agent followed standard protocols:
37
- - `guard_check` called before editing production/shared files?
38
- - `heartbeat` called with meaningful context?
39
- - `change_log` called after production code changes?
40
- - `learning_add` called after resolving errors?
41
- - `followup_complete` called when user confirmed a task was done?
42
- - `feedback` captured after corrections?
43
-
44
- ### 6. Emotional Signals
45
- Detect the user's emotional state throughout the session. Look for:
46
- - Frustration: short replies, cursing, "no", "otra vez", repeated corrections, tone shifts
47
- - Flow state: long productive stretches, "perfecto", "sí", rapid-fire instructions
48
- - Satisfaction: praise, "bien", "genial", accepting work without pushback
49
- - Disengagement: shorter messages over time, "ok", "vale", stopping mid-task
50
- - Stress: urgency words, deadlines, multiple tasks at once
51
- For each signal, note the approximate point in the session (early/mid/late) and what triggered it.
52
-
53
- ### 7. Abandoned Projects
54
- Detect work that was started but not finished in this session:
55
- - Tasks the user mentioned wanting to do but never got to
56
- - Work that was interrupted by something else and never resumed
57
- - Features partially implemented then dropped
58
- - Investigations started but conclusions never reached
59
- Only flag if the work was NOT captured in a followup or reminder.
60
-
61
- ### 9. Skill Candidates (Reusable Procedures)
62
- Detect multi-step tasks that were completed successfully and could be reused:
63
- - Tasks that required 3+ distinct steps to complete
64
- - Tasks where the agent followed a clear sequence of actions
65
- - Procedures that are likely to be repeated in the future
66
- - Examples: deploying code, configuring a service, running an audit, setting up infrastructure
67
-
68
- For each candidate, extract:
69
- - The full step-by-step procedure (what was actually done, in order)
70
- - Tags describing the domain (e.g., "shopify", "chrome", "deploy")
71
- - Trigger phrases that would indicate this procedure is needed (e.g., "deploy extension", "push theme")
72
- - Any gotchas or warnings discovered during execution
73
- - Whether the procedure looks scriptable (`scriptable: true|false`)
74
- - Automation scope: `read-only|local|remote`
75
- - Candidate params if the procedure clearly has repeated inputs (e.g. store, version, environment)
76
- - Which steps are automatable vs still manual
77
-
78
- Only flag if the procedure was SUCCESSFUL (the task was completed without major failures).
79
- Do NOT flag trivial tasks (single-step actions, simple file edits, quick lookups).
80
-
81
- ### 8. Productivity Patterns
82
- Analyze how the session went in terms of efficiency:
83
- - How many times did the agent need correction before getting it right?
84
- - Did the agent anticipate needs or always wait for instructions?
85
- - Were there unnecessary back-and-forths that a better approach would have avoided?
86
- - Did the agent propose solutions or just ask questions?
87
- - Tool usage: which tools were used most? Any tools used unnecessarily or not used when they should have been?
88
-
89
- ## Output Format
90
-
91
- Return ONLY valid JSON. No markdown code fences. No explanation text before or after.
92
-
93
- ```json
94
- {
95
- "session_id": "filename.jsonl",
96
- "findings": [
97
- {
98
- "type": "uncaptured_correction",
99
- "confidence": 0.9,
100
- "impact": "high",
101
- "reversibility": "reversible",
102
- "evidence": {
103
- "type": "transcript",
104
- "session_id": "filename.jsonl",
105
- "message_index": 42,
106
- "quote": "Exact user words (max 150 chars)"
107
- },
108
- "dedupe_key": "correction-<short-hash-of-content>",
109
- "action_class": "auto_apply",
110
- "description": "What the agent should have learned",
111
- "suggested_action": "learning_add",
112
- "suggested_content": {
113
- "category": "process|code|ui|communication",
114
- "title": "Short title for the learning",
115
- "content": "Full learning content"
116
- }
117
- },
118
- {
119
- "type": "self_corrected_error",
120
- "confidence": 0.85,
121
- "impact": "medium",
122
- "reversibility": "reversible",
123
- "evidence": {
124
- "type": "transcript",
125
- "session_id": "filename.jsonl",
126
- "message_index": 15,
127
- "quote": "What the agent did wrong and how it found the right answer"
128
- },
129
- "dedupe_key": "selfcorrect-<short-hash>",
130
- "action_class": "auto_apply",
131
- "description": "Knowledge gap identified",
132
- "suggested_action": "learning_add",
133
- "suggested_content": {
134
- "category": "code",
135
- "title": "Short title",
136
- "content": "Full learning content"
137
- }
138
- },
139
- {
140
- "type": "unformalised_idea",
141
- "confidence": 0.7,
142
- "impact": "medium",
143
- "reversibility": "reversible",
144
- "evidence": {
145
- "type": "transcript",
146
- "session_id": "filename.jsonl",
147
- "message_index": 88,
148
- "quote": "User's exact words"
149
- },
150
- "dedupe_key": "idea-<short-hash>",
151
- "action_class": "draft_for_morning",
152
- "description": "What the idea is about",
153
- "suggested_action": "followup_create",
154
- "suggested_content": {
155
- "description": "Followup description",
156
- "date": "YYYY-MM-DD or empty"
157
- }
158
- },
159
- {
160
- "type": "missed_commitment",
161
- "confidence": 0.8,
162
- "impact": "medium",
163
- "reversibility": "reversible",
164
- "evidence": {
165
- "type": "transcript",
166
- "session_id": "filename.jsonl",
167
- "message_index": 102,
168
- "quote": "User's exact words"
169
- },
170
- "dedupe_key": "commitment-<short-hash>",
171
- "action_class": "auto_apply",
172
- "description": "What was promised",
173
- "suggested_action": "followup_create",
174
- "suggested_content": {
175
- "description": "Followup description",
176
- "date": "YYYY-MM-DD"
177
- }
178
- },
179
- {
180
- "type": "protocol_violation",
181
- "confidence": 0.95,
182
- "impact": "low",
183
- "reversibility": "reversible",
184
- "evidence": {
185
- "type": "transcript",
186
- "session_id": "filename.jsonl",
187
- "message_index": 50,
188
- "quote": "What happened"
189
- },
190
- "dedupe_key": "protocol-<protocol-name>-<short-hash>",
191
- "action_class": "auto_apply",
192
- "description": "Which protocol was violated and how",
193
- "suggested_action": "learning_add",
194
- "suggested_content": {
195
- "category": "process",
196
- "title": "Protocol compliance: <protocol name>",
197
- "content": "Details of what should have been done"
198
- }
199
- }
200
- ],
201
- "emotional_timeline": [
202
- {
203
- "phase": "early|mid|late",
204
- "emotion": "frustrated|flow|satisfied|disengaged|stressed|neutral",
205
- "trigger": "What caused this emotional state (max 100 chars)",
206
- "intensity": 0.8
207
- }
208
- ],
209
-
210
- "abandoned_projects": [
211
- {
212
- "description": "What was started but not finished",
213
- "reason": "interrupted|dropped|forgotten|deferred",
214
- "has_followup": false
215
- }
216
- ],
217
-
218
- "skill_candidates": [
219
- {
220
- "name": "Short name for the procedure (e.g., Deploy Chrome Extension)",
221
- "description": "What this procedure accomplishes (1-2 sentences)",
222
- "steps": [
223
- "Step 1: What was done first",
224
- "Step 2: What was done next",
225
- "Step 3: etc."
226
- ],
227
- "tags": ["domain1", "domain2"],
228
- "trigger_phrases": ["phrase that would trigger this", "another trigger"],
229
- "gotchas": ["Warning or caveat discovered during execution"],
230
- "scriptable": false,
231
- "automation_scope": "read-only|local|remote",
232
- "candidate_params": {
233
- "param_name": {
234
- "type": "string|integer|number|boolean",
235
- "required": true
236
- }
237
- },
238
- "automatable_steps": ["Step that could be automated"],
239
- "manual_steps": ["Step that still needs human judgment"],
240
- "evidence": {
241
- "type": "transcript",
242
- "session_id": "filename.jsonl",
243
- "message_index": 10,
244
- "quote": "Start of the multi-step task"
245
- },
246
- "confidence": 0.85
247
- }
248
- ],
249
-
250
- "productivity_score": {
251
- "corrections_needed": 0,
252
- "proactivity": "reactive|mixed|proactive",
253
- "unnecessary_roundtrips": 0,
254
- "tool_efficiency": "efficient|mixed|wasteful",
255
- "notable_tools": ["tool1", "tool2"],
256
- "summary": "One sentence assessment of session productivity"
257
- },
258
-
259
- "protocol_summary": {
260
- "guard_check": {"required": 0, "executed": 0},
261
- "heartbeat": {"total": 0, "with_context": 0},
262
- "change_log": {"edits": 0, "logged": 0},
263
- "learning_capture": {"errors": 0, "captured": 0},
264
- "followup_complete": {"confirmed_done": 0, "marked": 0}
265
- }
266
- }
267
- ```
268
-
269
- ## Rules
270
-
271
- - Be SPECIFIC. Quote the user's exact words in evidence.
272
- - Only flag REAL issues. If the agent did capture something correctly, do not flag it.
273
- - `confidence` is 0.0-1.0. Be honest -- if you're unsure, use a lower value.
274
- - `action_class`: use `auto_apply` when confidence >= 0.8 and the action is reversible. Use `draft_for_morning` when confidence < 0.8 or when the impact is high.
275
- - `dedupe_key`: create a short, deterministic key from the finding type + core content so duplicate findings across runs are suppressed.
276
- - Do NOT use any specific agent name -- refer to "the agent" throughout.
277
- - If no issues found, return `{"session_id": "...", "findings": [], "protocol_summary": {...}}`.
278
- - Do NOT invent problems. Empty findings are perfectly fine.
279
- - Respond in the user's language (check calibration.json if available). The JSON keys stay in English, but `description`, `title`, `content` fields should be in the user's language.
280
-
281
- ## Context
282
-
283
- Read the session transcript at this path: {{CONTEXT_FILE}}
284
-
285
- Analyze session: {{SESSION_ID}}