@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,187 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- import uuid
4
- import json
5
- import re
6
- from difflib import SequenceMatcher
7
- from typing import Dict, Any
8
-
9
- from brain.runtime.instrumentation import emit_event
10
- from brain.runtime import state_store
11
- from brain.runtime.memory import provenance, store
12
- from brain.runtime.security import redaction
13
-
14
-
15
- LOGFILE = state_store.reports_dir() / "brain_memory.log.jsonl"
16
- _NEAR_DUPLICATE_SIMILARITY = 0.85
17
-
18
-
19
- def _normalize_summary(text: str) -> str:
20
- return re.sub(r"\s+", " ", str(text or "").strip().lower())
21
-
22
-
23
- def _tokenize(text: str) -> set[str]:
24
- return {token for token in re.findall(r"[a-z0-9]+", _normalize_summary(text))}
25
-
26
-
27
- def _summary_similarity(left: str, right: str) -> float:
28
- left_tokens = _tokenize(left)
29
- right_tokens = _tokenize(right)
30
- token_similarity = 0.0
31
- if left_tokens and right_tokens:
32
- overlap = len(left_tokens & right_tokens)
33
- union = len(left_tokens | right_tokens)
34
- token_similarity = overlap / max(1, union)
35
- sequence_similarity = SequenceMatcher(None, _normalize_summary(left), _normalize_summary(right)).ratio()
36
- return max(token_similarity, sequence_similarity)
37
-
38
-
39
- def _ranges_overlap(left: Dict[str, Any], right: Dict[str, Any]) -> bool:
40
- if str(left.get("path") or "") != str(right.get("path") or ""):
41
- return False
42
-
43
- def _as_int(value: Any) -> int | None:
44
- try:
45
- return int(value) if value is not None else None
46
- except Exception:
47
- return None
48
-
49
- left_start = _as_int(left.get("start_line"))
50
- left_end = _as_int(left.get("end_line")) or left_start
51
- right_start = _as_int(right.get("start_line"))
52
- right_end = _as_int(right.get("end_line")) or right_start
53
-
54
- if left_start is None and right_start is None:
55
- return True
56
- if left_start is None or right_start is None:
57
- return False
58
- return max(left_start, right_start) <= min(left_end or left_start, right_end or right_start)
59
-
60
-
61
- def _shares_provenance_anchor(left: Dict[str, Any], right: Dict[str, Any]) -> bool:
62
- left_meta = provenance.normalize_metadata(left)
63
- right_meta = provenance.normalize_metadata(right)
64
- left_prov = left_meta.get("provenance") if isinstance(left_meta.get("provenance"), dict) else {}
65
- right_prov = right_meta.get("provenance") if isinstance(right_meta.get("provenance"), dict) else {}
66
-
67
- left_conv = left_prov.get("conversation") if isinstance(left_prov.get("conversation"), dict) else {}
68
- right_conv = right_prov.get("conversation") if isinstance(right_prov.get("conversation"), dict) else {}
69
- if left_conv.get("message_id") and left_conv.get("message_id") == right_conv.get("message_id"):
70
- return True
71
-
72
- left_transcript = left_prov.get("transcript_anchor") if isinstance(left_prov.get("transcript_anchor"), dict) else {}
73
- right_transcript = right_prov.get("transcript_anchor") if isinstance(right_prov.get("transcript_anchor"), dict) else {}
74
- if left_transcript.get("path") and right_transcript.get("path") and _ranges_overlap(left_transcript, right_transcript):
75
- return True
76
-
77
- left_refs = {str(item) for item in left_prov.get("source_references") or [] if str(item).strip()}
78
- right_refs = {str(item) for item in right_prov.get("source_references") or [] if str(item).strip()}
79
- return bool(left_refs & right_refs)
80
-
81
-
82
- def _find_near_duplicate_candidate(conn, source_event_id: int, summary: str, metadata: Dict[str, Any]) -> str | None:
83
- rows = conn.execute(
84
- """
85
- SELECT candidate_id, distilled_summary, metadata_json
86
- FROM candidates
87
- WHERE source_event_id != ?
88
- ORDER BY created_at DESC, candidate_id DESC
89
- LIMIT 250
90
- """,
91
- (source_event_id,),
92
- ).fetchall()
93
- normalized_summary = _normalize_summary(summary)
94
- for row in rows:
95
- existing_summary = str(row["distilled_summary"] if isinstance(row, dict) else row[1] or "")
96
- similarity = _summary_similarity(normalized_summary, existing_summary)
97
- if similarity < _NEAR_DUPLICATE_SIMILARITY:
98
- continue
99
- try:
100
- existing_metadata = json.loads(row["metadata_json"] if isinstance(row, dict) else row[2] or "{}")
101
- except Exception:
102
- existing_metadata = {}
103
- if _shares_provenance_anchor(metadata, existing_metadata):
104
- return str(row["candidate_id"] if isinstance(row, dict) else row[0])
105
- return None
106
-
107
-
108
- def create_candidate(
109
- source_event_id: int,
110
- distilled_summary: str,
111
- verification_points: list[str],
112
- confidence_score: float,
113
- metadata: Dict[str, Any] | None = None,
114
- ) -> Dict[str, Any]:
115
- summary, redacted = redaction.redact_text(distilled_summary)
116
- verification_lines = []
117
- for point in verification_points:
118
- clean, _ = redaction.redact_text(str(point))
119
- verification_lines.append(clean)
120
-
121
- normalized_metadata = provenance.normalize_metadata(metadata, source="candidate")
122
-
123
- conn = store.connect()
124
- exact_row = conn.execute(
125
- "SELECT candidate_id FROM candidates WHERE source_event_id=? AND distilled_summary=?",
126
- (source_event_id, summary),
127
- ).fetchone()
128
- if exact_row:
129
- conn.close()
130
- emit_event(LOGFILE, "brain_memory_candidate_duplicate", status="ok", source_event_id=source_event_id)
131
- return {"candidate_id": exact_row[0], "duplicate": True}
132
-
133
- near_duplicate_id = _find_near_duplicate_candidate(conn, source_event_id, summary, normalized_metadata)
134
- if near_duplicate_id:
135
- conn.close()
136
- emit_event(LOGFILE, "brain_memory_candidate_duplicate", status="ok", source_event_id=source_event_id, duplicate_kind="near")
137
- return {"candidate_id": near_duplicate_id, "duplicate": True}
138
-
139
- candidate_id = str(uuid.uuid4())
140
- verification_status = "verified" if verification_lines else "unverified"
141
- conn.execute(
142
- """
143
- INSERT INTO candidates (
144
- candidate_id, source_event_id, distilled_summary, verification_points,
145
- confidence_score, status, verification_status, metadata_json, schema_version
146
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
147
- """,
148
- (
149
- candidate_id,
150
- source_event_id,
151
- summary,
152
- "\n".join(verification_lines),
153
- confidence_score,
154
- "pending",
155
- verification_status,
156
- json.dumps(normalized_metadata, ensure_ascii=False),
157
- store.SCHEMA_VERSION,
158
- ),
159
- )
160
- conn.execute(
161
- "INSERT INTO memory_events (event_type, source, details_json, schema_version) VALUES (?, ?, ?, ?)",
162
- (
163
- "candidate_created",
164
- str(source_event_id),
165
- json.dumps({"candidate_id": candidate_id, "redacted": redacted, "verification_status": verification_status}),
166
- store.SCHEMA_VERSION,
167
- ),
168
- )
169
- conn.commit()
170
- conn.close()
171
- emit_event(LOGFILE, "brain_memory_candidate_created", status="ok", source_event_id=source_event_id, redacted=redacted)
172
- return {"candidate_id": candidate_id, "duplicate": False}
173
-
174
-
175
- def get_candidate(candidate_id: str) -> Dict[str, Any] | None:
176
- conn = store.connect()
177
- row = conn.execute(
178
- """
179
- SELECT candidate_id, source_event_id, distilled_summary, verification_points,
180
- confidence_score, status, verification_status, metadata_json
181
- FROM candidates
182
- WHERE candidate_id=?
183
- """,
184
- (candidate_id,),
185
- ).fetchone()
186
- conn.close()
187
- return dict(row) if row else None
3
+ from ocmemog.runtime.memory.candidate import * # noqa: F401,F403