@simbimbo/memory-ocmemog 0.1.11 → 0.1.13

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 (102) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +83 -18
  3. package/brain/runtime/__init__.py +2 -12
  4. package/brain/runtime/config.py +1 -24
  5. package/brain/runtime/inference.py +1 -151
  6. package/brain/runtime/instrumentation.py +1 -15
  7. package/brain/runtime/memory/__init__.py +3 -13
  8. package/brain/runtime/memory/api.py +1 -1219
  9. package/brain/runtime/memory/candidate.py +1 -185
  10. package/brain/runtime/memory/conversation_state.py +1 -1823
  11. package/brain/runtime/memory/distill.py +1 -344
  12. package/brain/runtime/memory/embedding_engine.py +1 -92
  13. package/brain/runtime/memory/freshness.py +1 -112
  14. package/brain/runtime/memory/health.py +1 -40
  15. package/brain/runtime/memory/integrity.py +1 -186
  16. package/brain/runtime/memory/memory_consolidation.py +1 -58
  17. package/brain/runtime/memory/memory_links.py +1 -107
  18. package/brain/runtime/memory/memory_salience.py +1 -233
  19. package/brain/runtime/memory/memory_synthesis.py +1 -31
  20. package/brain/runtime/memory/memory_taxonomy.py +1 -33
  21. package/brain/runtime/memory/pondering_engine.py +1 -654
  22. package/brain/runtime/memory/promote.py +1 -277
  23. package/brain/runtime/memory/provenance.py +1 -406
  24. package/brain/runtime/memory/reinforcement.py +1 -71
  25. package/brain/runtime/memory/retrieval.py +1 -210
  26. package/brain/runtime/memory/semantic_search.py +1 -64
  27. package/brain/runtime/memory/store.py +1 -429
  28. package/brain/runtime/memory/unresolved_state.py +1 -91
  29. package/brain/runtime/memory/vector_index.py +1 -323
  30. package/brain/runtime/model_roles.py +1 -9
  31. package/brain/runtime/model_router.py +1 -22
  32. package/brain/runtime/providers.py +1 -66
  33. package/brain/runtime/security/redaction.py +1 -12
  34. package/brain/runtime/state_store.py +1 -23
  35. package/brain/runtime/storage_paths.py +1 -39
  36. package/docs/architecture/memory.md +20 -24
  37. package/docs/release-checklist.md +19 -6
  38. package/docs/usage.md +33 -17
  39. package/index.ts +8 -1
  40. package/ocmemog/__init__.py +11 -0
  41. package/ocmemog/doctor.py +1255 -0
  42. package/ocmemog/runtime/__init__.py +18 -0
  43. package/ocmemog/runtime/_compat_bridge.py +28 -0
  44. package/ocmemog/runtime/config.py +34 -0
  45. package/ocmemog/runtime/identity.py +115 -0
  46. package/ocmemog/runtime/inference.py +163 -0
  47. package/ocmemog/runtime/instrumentation.py +20 -0
  48. package/ocmemog/runtime/memory/__init__.py +91 -0
  49. package/ocmemog/runtime/memory/api.py +1594 -0
  50. package/ocmemog/runtime/memory/candidate.py +192 -0
  51. package/ocmemog/runtime/memory/conversation_state.py +1831 -0
  52. package/ocmemog/runtime/memory/distill.py +282 -0
  53. package/ocmemog/runtime/memory/embedding_engine.py +151 -0
  54. package/ocmemog/runtime/memory/freshness.py +114 -0
  55. package/ocmemog/runtime/memory/health.py +93 -0
  56. package/ocmemog/runtime/memory/integrity.py +208 -0
  57. package/ocmemog/runtime/memory/memory_consolidation.py +60 -0
  58. package/ocmemog/runtime/memory/memory_links.py +109 -0
  59. package/ocmemog/runtime/memory/memory_salience.py +235 -0
  60. package/ocmemog/runtime/memory/memory_synthesis.py +33 -0
  61. package/ocmemog/runtime/memory/memory_taxonomy.py +35 -0
  62. package/ocmemog/runtime/memory/pondering_engine.py +681 -0
  63. package/ocmemog/runtime/memory/promote.py +279 -0
  64. package/ocmemog/runtime/memory/provenance.py +408 -0
  65. package/ocmemog/runtime/memory/reinforcement.py +73 -0
  66. package/ocmemog/runtime/memory/retrieval.py +224 -0
  67. package/ocmemog/runtime/memory/semantic_search.py +66 -0
  68. package/ocmemog/runtime/memory/store.py +433 -0
  69. package/ocmemog/runtime/memory/unresolved_state.py +93 -0
  70. package/ocmemog/runtime/memory/vector_index.py +411 -0
  71. package/ocmemog/runtime/model_roles.py +15 -0
  72. package/ocmemog/runtime/model_router.py +28 -0
  73. package/ocmemog/runtime/providers.py +78 -0
  74. package/ocmemog/runtime/roles.py +92 -0
  75. package/ocmemog/runtime/security/__init__.py +8 -0
  76. package/ocmemog/runtime/security/redaction.py +17 -0
  77. package/ocmemog/runtime/state_store.py +32 -0
  78. package/ocmemog/runtime/storage_paths.py +70 -0
  79. package/ocmemog/sidecar/app.py +421 -60
  80. package/ocmemog/sidecar/compat.py +50 -13
  81. package/ocmemog/sidecar/transcript_watcher.py +327 -242
  82. package/openclaw.plugin.json +4 -0
  83. package/package.json +1 -1
  84. package/scripts/ocmemog-backfill-vectors.py +5 -3
  85. package/scripts/ocmemog-continuity-benchmark.py +1 -1
  86. package/scripts/ocmemog-demo.py +1 -1
  87. package/scripts/ocmemog-doctor.py +15 -0
  88. package/scripts/ocmemog-install.sh +29 -7
  89. package/scripts/ocmemog-integrated-proof.py +374 -0
  90. package/scripts/ocmemog-reindex-vectors.py +5 -3
  91. package/scripts/ocmemog-release-check.sh +330 -0
  92. package/scripts/ocmemog-sidecar.sh +4 -2
  93. package/scripts/ocmemog-test-rig.py +5 -3
  94. package/brain/runtime/memory/artifacts.py +0 -33
  95. package/brain/runtime/memory/context_builder.py +0 -112
  96. package/brain/runtime/memory/interaction_memory.py +0 -57
  97. package/brain/runtime/memory/memory_gate.py +0 -38
  98. package/brain/runtime/memory/memory_graph.py +0 -54
  99. package/brain/runtime/memory/person_identity.py +0 -83
  100. package/brain/runtime/memory/person_memory.py +0 -138
  101. package/brain/runtime/memory/sentiment_memory.py +0 -67
  102. package/brain/runtime/memory/tool_catalog.py +0 -68
@@ -1,431 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- import sqlite3
4
- import queue
5
- import threading
6
- from pathlib import Path
7
- from brain.runtime import state_store
8
-
9
- SCHEMA_VERSION = "v1"
10
-
11
- MEMORY_TABLES = (
12
- "knowledge",
13
- "preferences",
14
- "identity",
15
- "reflections",
16
- "directives",
17
- "tasks",
18
- "runbooks",
19
- "lessons",
20
- )
21
-
22
- SCHEMA_SQL = """
23
- CREATE TABLE IF NOT EXISTS memory_events (
24
- id INTEGER PRIMARY KEY AUTOINCREMENT,
25
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
26
- event_type TEXT NOT NULL,
27
- source TEXT,
28
- details_json TEXT DEFAULT '{}',
29
- schema_version TEXT NOT NULL
30
- );
31
-
32
- CREATE TABLE IF NOT EXISTS environment_cognition (
33
- id INTEGER PRIMARY KEY AUTOINCREMENT,
34
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
35
- source TEXT,
36
- confidence REAL NOT NULL DEFAULT 1.0,
37
- metadata_json TEXT DEFAULT '{}',
38
- content TEXT NOT NULL,
39
- schema_version TEXT NOT NULL
40
- );
41
-
42
- CREATE TABLE IF NOT EXISTS experiences (
43
- id INTEGER PRIMARY KEY AUTOINCREMENT,
44
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
45
- task_id TEXT,
46
- outcome TEXT,
47
- reward_score REAL,
48
- confidence REAL NOT NULL DEFAULT 1.0,
49
- memory_reference TEXT,
50
- experience_type TEXT,
51
- source_module TEXT,
52
- metadata_json TEXT DEFAULT '{}',
53
- schema_version TEXT NOT NULL
54
- );
55
-
56
- CREATE TABLE IF NOT EXISTS directives (
57
- id INTEGER PRIMARY KEY AUTOINCREMENT,
58
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
59
- source TEXT,
60
- confidence REAL NOT NULL DEFAULT 1.0,
61
- metadata_json TEXT DEFAULT '{}',
62
- content TEXT NOT NULL,
63
- schema_version TEXT NOT NULL
64
- );
65
-
66
- CREATE TABLE IF NOT EXISTS candidates (
67
- candidate_id TEXT PRIMARY KEY,
68
- source_event_id INTEGER,
69
- distilled_summary TEXT,
70
- verification_points TEXT,
71
- confidence_score REAL,
72
- status TEXT NOT NULL DEFAULT 'pending',
73
- verification_status TEXT NOT NULL DEFAULT 'unverified',
74
- metadata_json TEXT DEFAULT '{}',
75
- created_at TEXT NOT NULL DEFAULT (datetime('now')),
76
- updated_at TEXT NOT NULL DEFAULT (datetime('now')),
77
- schema_version TEXT NOT NULL
78
- );
79
-
80
- CREATE TABLE IF NOT EXISTS promotions (
81
- id INTEGER PRIMARY KEY AUTOINCREMENT,
82
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
83
- candidate_id TEXT,
84
- source TEXT,
85
- confidence REAL NOT NULL DEFAULT 1.0,
86
- status TEXT NOT NULL DEFAULT 'promoted',
87
- decision_reason TEXT,
88
- metadata_json TEXT DEFAULT '{}',
89
- content TEXT NOT NULL,
90
- schema_version TEXT NOT NULL
91
- );
92
-
93
- CREATE TABLE IF NOT EXISTS demotions (
94
- id INTEGER PRIMARY KEY AUTOINCREMENT,
95
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
96
- memory_reference TEXT NOT NULL,
97
- previous_confidence REAL,
98
- new_confidence REAL,
99
- reason TEXT,
100
- schema_version TEXT NOT NULL
101
- );
102
-
103
- CREATE TABLE IF NOT EXISTS cold_storage (
104
- id INTEGER PRIMARY KEY AUTOINCREMENT,
105
- archived_at TEXT NOT NULL DEFAULT (datetime('now')),
106
- source_table TEXT NOT NULL,
107
- source_id INTEGER NOT NULL,
108
- content TEXT NOT NULL,
109
- metadata_json TEXT DEFAULT '{}',
110
- reason TEXT,
111
- schema_version TEXT NOT NULL
112
- );
113
-
114
- CREATE TABLE IF NOT EXISTS knowledge (
115
- id INTEGER PRIMARY KEY AUTOINCREMENT,
116
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
117
- source TEXT,
118
- confidence REAL NOT NULL DEFAULT 1.0,
119
- metadata_json TEXT DEFAULT '{}',
120
- content TEXT NOT NULL,
121
- schema_version TEXT NOT NULL
122
- );
123
-
124
- CREATE TABLE IF NOT EXISTS preferences (
125
- id INTEGER PRIMARY KEY AUTOINCREMENT,
126
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
127
- source TEXT,
128
- confidence REAL NOT NULL DEFAULT 1.0,
129
- metadata_json TEXT DEFAULT '{}',
130
- content TEXT NOT NULL,
131
- schema_version TEXT NOT NULL
132
- );
133
-
134
- CREATE TABLE IF NOT EXISTS identity (
135
- id INTEGER PRIMARY KEY AUTOINCREMENT,
136
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
137
- source TEXT,
138
- confidence REAL NOT NULL DEFAULT 1.0,
139
- metadata_json TEXT DEFAULT '{}',
140
- content TEXT NOT NULL,
141
- schema_version TEXT NOT NULL
142
- );
143
-
144
- CREATE TABLE IF NOT EXISTS runbooks (
145
- id INTEGER PRIMARY KEY AUTOINCREMENT,
146
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
147
- source TEXT,
148
- confidence REAL NOT NULL DEFAULT 1.0,
149
- metadata_json TEXT DEFAULT '{}',
150
- content TEXT NOT NULL,
151
- schema_version TEXT NOT NULL
152
- );
153
-
154
- CREATE TABLE IF NOT EXISTS lessons (
155
- id INTEGER PRIMARY KEY AUTOINCREMENT,
156
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
157
- source TEXT,
158
- confidence REAL NOT NULL DEFAULT 1.0,
159
- metadata_json TEXT DEFAULT '{}',
160
- content TEXT NOT NULL,
161
- schema_version TEXT NOT NULL
162
- );
163
-
164
- CREATE TABLE IF NOT EXISTS reflections (
165
- id INTEGER PRIMARY KEY AUTOINCREMENT,
166
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
167
- source TEXT,
168
- confidence REAL NOT NULL DEFAULT 1.0,
169
- metadata_json TEXT DEFAULT '{}',
170
- content TEXT NOT NULL,
171
- schema_version TEXT NOT NULL
172
- );
173
-
174
- CREATE TABLE IF NOT EXISTS tasks (
175
- id INTEGER PRIMARY KEY AUTOINCREMENT,
176
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
177
- source TEXT,
178
- confidence REAL NOT NULL DEFAULT 1.0,
179
- metadata_json TEXT DEFAULT '{}',
180
- content TEXT NOT NULL,
181
- schema_version TEXT NOT NULL
182
- );
183
-
184
- CREATE TABLE IF NOT EXISTS memory_index (
185
- id INTEGER PRIMARY KEY AUTOINCREMENT,
186
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
187
- source TEXT,
188
- confidence REAL NOT NULL DEFAULT 1.0,
189
- metadata_json TEXT DEFAULT '{}',
190
- content TEXT NOT NULL,
191
- schema_version TEXT NOT NULL
192
- );
193
-
194
- CREATE TABLE IF NOT EXISTS vector_embeddings (
195
- id TEXT PRIMARY KEY,
196
- source_type TEXT NOT NULL,
197
- source_id TEXT NOT NULL,
198
- embedding TEXT NOT NULL,
199
- created_at TEXT NOT NULL DEFAULT (datetime('now'))
200
- );
201
-
202
- CREATE TABLE IF NOT EXISTS artifacts (
203
- artifact_id TEXT PRIMARY KEY,
204
- artifact_type TEXT,
205
- source_path TEXT,
206
- content_hash TEXT,
207
- metadata TEXT,
208
- created_at TIMESTAMP DEFAULT (datetime('now'))
209
- );
210
-
211
- CREATE TABLE IF NOT EXISTS conversation_turns (
212
- id INTEGER PRIMARY KEY AUTOINCREMENT,
213
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
214
- conversation_id TEXT,
215
- session_id TEXT,
216
- thread_id TEXT,
217
- message_id TEXT,
218
- role TEXT NOT NULL,
219
- content TEXT NOT NULL,
220
- transcript_path TEXT,
221
- transcript_offset INTEGER,
222
- transcript_end_offset INTEGER,
223
- source TEXT,
224
- metadata_json TEXT DEFAULT '{}',
225
- schema_version TEXT NOT NULL
226
- );
227
-
228
- CREATE INDEX IF NOT EXISTS idx_conversation_turns_conversation ON conversation_turns(conversation_id, id DESC);
229
- CREATE INDEX IF NOT EXISTS idx_conversation_turns_session ON conversation_turns(session_id, id DESC);
230
- CREATE INDEX IF NOT EXISTS idx_conversation_turns_thread ON conversation_turns(thread_id, id DESC);
231
- CREATE INDEX IF NOT EXISTS idx_conversation_turns_message ON conversation_turns(message_id);
232
-
233
- CREATE TABLE IF NOT EXISTS conversation_checkpoints (
234
- id INTEGER PRIMARY KEY AUTOINCREMENT,
235
- timestamp TEXT NOT NULL DEFAULT (datetime('now')),
236
- conversation_id TEXT,
237
- session_id TEXT,
238
- thread_id TEXT,
239
- turn_start_id INTEGER,
240
- turn_end_id INTEGER,
241
- checkpoint_kind TEXT NOT NULL DEFAULT 'manual',
242
- summary TEXT NOT NULL,
243
- latest_user_ask TEXT,
244
- last_assistant_commitment TEXT,
245
- open_loops_json TEXT DEFAULT '[]',
246
- pending_actions_json TEXT DEFAULT '[]',
247
- parent_checkpoint_id INTEGER,
248
- root_checkpoint_id INTEGER,
249
- depth INTEGER NOT NULL DEFAULT 0,
250
- metadata_json TEXT DEFAULT '{}',
251
- schema_version TEXT NOT NULL
252
- );
253
-
254
- CREATE INDEX IF NOT EXISTS idx_conversation_checkpoints_conversation ON conversation_checkpoints(conversation_id, id DESC);
255
- CREATE INDEX IF NOT EXISTS idx_conversation_checkpoints_session ON conversation_checkpoints(session_id, id DESC);
256
- CREATE INDEX IF NOT EXISTS idx_conversation_checkpoints_thread ON conversation_checkpoints(thread_id, id DESC);
257
-
258
- CREATE TABLE IF NOT EXISTS conversation_state (
259
- id INTEGER PRIMARY KEY AUTOINCREMENT,
260
- scope_type TEXT NOT NULL,
261
- scope_id TEXT NOT NULL,
262
- conversation_id TEXT,
263
- session_id TEXT,
264
- thread_id TEXT,
265
- latest_user_turn_id INTEGER,
266
- latest_assistant_turn_id INTEGER,
267
- latest_user_ask TEXT,
268
- last_assistant_commitment TEXT,
269
- open_loops_json TEXT DEFAULT '[]',
270
- pending_actions_json TEXT DEFAULT '[]',
271
- unresolved_state_json TEXT DEFAULT '[]',
272
- latest_checkpoint_id INTEGER,
273
- metadata_json TEXT DEFAULT '{}',
274
- updated_at TEXT NOT NULL DEFAULT (datetime('now')),
275
- schema_version TEXT NOT NULL,
276
- UNIQUE(scope_type, scope_id)
277
- );
278
-
279
- CREATE INDEX IF NOT EXISTS idx_conversation_state_conversation ON conversation_state(conversation_id);
280
- CREATE INDEX IF NOT EXISTS idx_conversation_state_session ON conversation_state(session_id);
281
- CREATE INDEX IF NOT EXISTS idx_conversation_state_thread ON conversation_state(thread_id);
282
- """
283
-
284
- _WRITE_QUEUE: "queue.Queue[tuple]" = queue.Queue()
285
- _WRITE_LOCK = threading.Lock()
286
- _WRITE_WORKER_STARTED = False
287
-
288
-
289
- def is_lock_error(exc: BaseException) -> bool:
290
- message = str(exc).lower()
291
- return isinstance(exc, sqlite3.OperationalError) and (
292
- "database is locked" in message
293
- or "database table is locked" in message
294
- or "busy" in message
295
- )
296
-
297
-
298
- def _write_worker() -> None:
299
- while True:
300
- fn, event, container = _WRITE_QUEUE.get()
301
- try:
302
- container["result"] = fn()
303
- except Exception as exc: # pragma: no cover
304
- container["error"] = exc
305
- finally:
306
- event.set()
307
- _WRITE_QUEUE.task_done()
308
-
309
-
310
- def _ensure_write_worker() -> None:
311
- global _WRITE_WORKER_STARTED
312
- with _WRITE_LOCK:
313
- if _WRITE_WORKER_STARTED:
314
- return
315
- thread = threading.Thread(target=_write_worker, daemon=True)
316
- thread.start()
317
- _WRITE_WORKER_STARTED = True
318
-
319
-
320
- def submit_write(fn, timeout: float = 30.0):
321
- _ensure_write_worker()
322
- event = threading.Event()
323
- container: dict = {}
324
- _WRITE_QUEUE.put((fn, event, container))
325
- if not event.wait(timeout=timeout):
326
- raise TimeoutError("write queue timeout")
327
- if "error" in container:
328
- raise container["error"]
329
- return container.get("result")
330
-
331
-
332
- def db_path() -> Path:
333
- return state_store.memory_db_path()
334
-
335
-
336
- _SCHEMA_READY = False
337
-
338
-
339
- def connect(*, ensure_schema: bool = True) -> sqlite3.Connection:
340
- global _SCHEMA_READY
341
- if ensure_schema and not _SCHEMA_READY:
342
- init_db()
343
- _SCHEMA_READY = True
344
- path = db_path()
345
- path.parent.mkdir(parents=True, exist_ok=True)
346
- conn = sqlite3.connect(str(path), timeout=30)
347
- conn.row_factory = sqlite3.Row
348
-
349
- conn.execute("PRAGMA journal_mode=WAL")
350
- conn.execute("PRAGMA busy_timeout=15000")
351
- conn.execute("PRAGMA synchronous=NORMAL")
352
- conn.execute("PRAGMA temp_store=MEMORY")
353
- conn.execute("PRAGMA cache_size=-20000")
354
- return conn
355
-
356
-
357
- def _ensure_column(conn: sqlite3.Connection, table: str, column: str, coltype: str) -> None:
358
- cols = [row[1] for row in conn.execute(f"PRAGMA table_info({table})").fetchall()]
359
- if column not in cols:
360
- conn.execute(f"ALTER TABLE {table} ADD COLUMN {column} {coltype}")
361
-
362
-
363
- def init_db() -> None:
364
- conn = connect(ensure_schema=False)
365
- conn.executescript(SCHEMA_SQL)
366
- _ensure_column(conn, "experiences", "experience_type", "TEXT")
367
- _ensure_column(conn, "experiences", "source_module", "TEXT")
368
- _ensure_column(conn, "experiences", "metadata_json", "TEXT DEFAULT '{}' ")
369
- _ensure_column(conn, "candidates", "status", "TEXT NOT NULL DEFAULT 'pending'")
370
- _ensure_column(conn, "candidates", "verification_status", "TEXT NOT NULL DEFAULT 'unverified'")
371
- _ensure_column(conn, "candidates", "created_at", "TEXT")
372
- _ensure_column(conn, "candidates", "updated_at", "TEXT")
373
- conn.execute("UPDATE candidates SET created_at=datetime('now') WHERE created_at IS NULL")
374
- conn.execute("UPDATE candidates SET updated_at=datetime('now') WHERE updated_at IS NULL")
375
- _ensure_column(conn, "promotions", "candidate_id", "TEXT")
376
- _ensure_column(conn, "promotions", "status", "TEXT NOT NULL DEFAULT 'promoted'")
377
- _ensure_column(conn, "promotions", "decision_reason", "TEXT")
378
- _ensure_column(conn, "conversation_turns", "conversation_id", "TEXT")
379
- _ensure_column(conn, "conversation_turns", "session_id", "TEXT")
380
- _ensure_column(conn, "conversation_turns", "thread_id", "TEXT")
381
- _ensure_column(conn, "conversation_turns", "message_id", "TEXT")
382
- _ensure_column(conn, "conversation_turns", "role", "TEXT NOT NULL DEFAULT 'unknown'")
383
- _ensure_column(conn, "conversation_turns", "content", "TEXT")
384
- _ensure_column(conn, "conversation_turns", "transcript_path", "TEXT")
385
- _ensure_column(conn, "conversation_turns", "transcript_offset", "INTEGER")
386
- _ensure_column(conn, "conversation_turns", "transcript_end_offset", "INTEGER")
387
- _ensure_column(conn, "conversation_turns", "source", "TEXT")
388
- _ensure_column(conn, "conversation_turns", "metadata_json", "TEXT DEFAULT '{}'")
389
- conn.execute("CREATE INDEX IF NOT EXISTS idx_conversation_turns_conversation ON conversation_turns(conversation_id, id DESC)")
390
- conn.execute("CREATE INDEX IF NOT EXISTS idx_conversation_turns_session ON conversation_turns(session_id, id DESC)")
391
- conn.execute("CREATE INDEX IF NOT EXISTS idx_conversation_turns_thread ON conversation_turns(thread_id, id DESC)")
392
- conn.execute("CREATE INDEX IF NOT EXISTS idx_conversation_turns_message ON conversation_turns(message_id)")
393
- _ensure_column(conn, "conversation_checkpoints", "conversation_id", "TEXT")
394
- _ensure_column(conn, "conversation_checkpoints", "session_id", "TEXT")
395
- _ensure_column(conn, "conversation_checkpoints", "thread_id", "TEXT")
396
- _ensure_column(conn, "conversation_checkpoints", "turn_start_id", "INTEGER")
397
- _ensure_column(conn, "conversation_checkpoints", "turn_end_id", "INTEGER")
398
- _ensure_column(conn, "conversation_checkpoints", "checkpoint_kind", "TEXT NOT NULL DEFAULT 'manual'")
399
- _ensure_column(conn, "conversation_checkpoints", "summary", "TEXT NOT NULL DEFAULT ''")
400
- _ensure_column(conn, "conversation_checkpoints", "latest_user_ask", "TEXT")
401
- _ensure_column(conn, "conversation_checkpoints", "last_assistant_commitment", "TEXT")
402
- _ensure_column(conn, "conversation_checkpoints", "open_loops_json", "TEXT DEFAULT '[]'")
403
- _ensure_column(conn, "conversation_checkpoints", "pending_actions_json", "TEXT DEFAULT '[]'")
404
- _ensure_column(conn, "conversation_checkpoints", "parent_checkpoint_id", "INTEGER")
405
- _ensure_column(conn, "conversation_checkpoints", "root_checkpoint_id", "INTEGER")
406
- _ensure_column(conn, "conversation_checkpoints", "depth", "INTEGER NOT NULL DEFAULT 0")
407
- _ensure_column(conn, "conversation_checkpoints", "metadata_json", "TEXT DEFAULT '{}'")
408
- conn.execute("CREATE INDEX IF NOT EXISTS idx_conversation_checkpoints_conversation ON conversation_checkpoints(conversation_id, id DESC)")
409
- conn.execute("CREATE INDEX IF NOT EXISTS idx_conversation_checkpoints_session ON conversation_checkpoints(session_id, id DESC)")
410
- conn.execute("CREATE INDEX IF NOT EXISTS idx_conversation_checkpoints_thread ON conversation_checkpoints(thread_id, id DESC)")
411
- _ensure_column(conn, "conversation_state", "scope_type", "TEXT")
412
- _ensure_column(conn, "conversation_state", "scope_id", "TEXT")
413
- _ensure_column(conn, "conversation_state", "conversation_id", "TEXT")
414
- _ensure_column(conn, "conversation_state", "session_id", "TEXT")
415
- _ensure_column(conn, "conversation_state", "thread_id", "TEXT")
416
- _ensure_column(conn, "conversation_state", "latest_user_turn_id", "INTEGER")
417
- _ensure_column(conn, "conversation_state", "latest_assistant_turn_id", "INTEGER")
418
- _ensure_column(conn, "conversation_state", "latest_user_ask", "TEXT")
419
- _ensure_column(conn, "conversation_state", "last_assistant_commitment", "TEXT")
420
- _ensure_column(conn, "conversation_state", "open_loops_json", "TEXT DEFAULT '[]'")
421
- _ensure_column(conn, "conversation_state", "pending_actions_json", "TEXT DEFAULT '[]'")
422
- _ensure_column(conn, "conversation_state", "unresolved_state_json", "TEXT DEFAULT '[]'")
423
- _ensure_column(conn, "conversation_state", "latest_checkpoint_id", "INTEGER")
424
- _ensure_column(conn, "conversation_state", "metadata_json", "TEXT DEFAULT '{}'")
425
- _ensure_column(conn, "conversation_state", "updated_at", "TEXT")
426
- conn.execute("CREATE UNIQUE INDEX IF NOT EXISTS idx_conversation_state_scope ON conversation_state(scope_type, scope_id)")
427
- conn.execute("CREATE INDEX IF NOT EXISTS idx_conversation_state_conversation ON conversation_state(conversation_id)")
428
- conn.execute("CREATE INDEX IF NOT EXISTS idx_conversation_state_session ON conversation_state(session_id)")
429
- conn.execute("CREATE INDEX IF NOT EXISTS idx_conversation_state_thread ON conversation_state(thread_id)")
430
- conn.commit()
431
- conn.close()
3
+ from ocmemog.runtime.memory.store import * # noqa: F401,F403
@@ -1,93 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- import sqlite3
4
- import time
5
- from typing import Dict, List
6
-
7
- from brain.runtime import state_store
8
- from brain.runtime.instrumentation import emit_event
9
-
10
- LOGFILE = state_store.reports_dir() / "brain_memory.log.jsonl"
11
-
12
- TYPES = {
13
- "unresolved_question",
14
- "paused_task",
15
- "interrupted_thread",
16
- "pending_decision",
17
- "incomplete_hypothesis",
18
- }
19
-
20
-
21
- def _connect() -> sqlite3.Connection:
22
- path = state_store.data_dir() / "unresolved_state.db"
23
- path.parent.mkdir(parents=True, exist_ok=True)
24
- conn = sqlite3.connect(str(path))
25
- conn.row_factory = sqlite3.Row
26
- conn.execute(
27
- """
28
- CREATE TABLE IF NOT EXISTS unresolved_state (
29
- state_id INTEGER PRIMARY KEY AUTOINCREMENT,
30
- state_type TEXT NOT NULL,
31
- reference TEXT,
32
- summary TEXT,
33
- created_at TEXT NOT NULL DEFAULT (datetime('now')),
34
- resolved INTEGER NOT NULL DEFAULT 0
35
- )
36
- """
37
- )
38
- return conn
39
-
40
-
41
- def add_unresolved_state(state_type: str, reference: str, summary: str) -> int:
42
- if state_type not in TYPES:
43
- state_type = "unresolved_question"
44
- conn = _connect()
45
- conn.execute(
46
- "INSERT INTO unresolved_state (state_type, reference, summary, created_at, resolved) VALUES (?, ?, ?, ?, 0)",
47
- (state_type, reference, summary, time.strftime("%Y-%m-%d %H:%M:%S")),
48
- )
49
- conn.commit()
50
- row = conn.execute("SELECT last_insert_rowid()").fetchone()
51
- conn.close()
52
- emit_event(LOGFILE, "brain_unresolved_state_added", status="ok", state_type=state_type)
53
- return int(row[0]) if row else 0
54
-
55
-
56
- def list_unresolved_state(limit: int = 20) -> List[Dict[str, object]]:
57
- conn = _connect()
58
- rows = conn.execute(
59
- "SELECT state_id, state_type, reference, summary, created_at FROM unresolved_state WHERE resolved=0 ORDER BY created_at DESC LIMIT ?",
60
- (limit,),
61
- ).fetchall()
62
- conn.close()
63
- return [dict(row) for row in rows]
64
-
65
-
66
- def resolve_unresolved_state(state_id: int) -> bool:
67
- conn = _connect()
68
- conn.execute("UPDATE unresolved_state SET resolved=1 WHERE state_id=?", (state_id,))
69
- conn.commit()
70
- conn.close()
71
- emit_event(LOGFILE, "brain_unresolved_state_resolved", status="ok", state_id=state_id)
72
- return True
73
-
74
-
75
- def list_unresolved_state_for_references(references: List[str], limit: int = 20) -> List[Dict[str, object]]:
76
- refs = [str(ref).strip() for ref in references if str(ref).strip()]
77
- if not refs:
78
- return []
79
- placeholders = ",".join("?" for _ in refs)
80
- conn = _connect()
81
- rows = conn.execute(
82
- f"SELECT state_id, state_type, reference, summary, created_at FROM unresolved_state WHERE resolved=0 AND reference IN ({placeholders}) ORDER BY created_at DESC LIMIT ?",
83
- (*refs, limit),
84
- ).fetchall()
85
- conn.close()
86
- return [dict(row) for row in rows]
87
-
88
-
89
- def count_unresolved_state() -> int:
90
- conn = _connect()
91
- row = conn.execute("SELECT COUNT(*) FROM unresolved_state WHERE resolved=0").fetchone()
92
- conn.close()
93
- return int(row[0]) if row else 0
3
+ from ocmemog.runtime.memory.unresolved_state import * # noqa: F401,F403