@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.
- package/CHANGELOG.md +30 -0
- package/README.md +83 -18
- package/brain/runtime/__init__.py +2 -12
- package/brain/runtime/config.py +1 -24
- package/brain/runtime/inference.py +1 -151
- package/brain/runtime/instrumentation.py +1 -15
- package/brain/runtime/memory/__init__.py +3 -13
- package/brain/runtime/memory/api.py +1 -1219
- package/brain/runtime/memory/candidate.py +1 -185
- package/brain/runtime/memory/conversation_state.py +1 -1823
- package/brain/runtime/memory/distill.py +1 -344
- package/brain/runtime/memory/embedding_engine.py +1 -92
- package/brain/runtime/memory/freshness.py +1 -112
- package/brain/runtime/memory/health.py +1 -40
- package/brain/runtime/memory/integrity.py +1 -186
- package/brain/runtime/memory/memory_consolidation.py +1 -58
- package/brain/runtime/memory/memory_links.py +1 -107
- package/brain/runtime/memory/memory_salience.py +1 -233
- package/brain/runtime/memory/memory_synthesis.py +1 -31
- package/brain/runtime/memory/memory_taxonomy.py +1 -33
- package/brain/runtime/memory/pondering_engine.py +1 -654
- package/brain/runtime/memory/promote.py +1 -277
- package/brain/runtime/memory/provenance.py +1 -406
- package/brain/runtime/memory/reinforcement.py +1 -71
- package/brain/runtime/memory/retrieval.py +1 -210
- package/brain/runtime/memory/semantic_search.py +1 -64
- package/brain/runtime/memory/store.py +1 -429
- package/brain/runtime/memory/unresolved_state.py +1 -91
- package/brain/runtime/memory/vector_index.py +1 -323
- package/brain/runtime/model_roles.py +1 -9
- package/brain/runtime/model_router.py +1 -22
- package/brain/runtime/providers.py +1 -66
- package/brain/runtime/security/redaction.py +1 -12
- package/brain/runtime/state_store.py +1 -23
- package/brain/runtime/storage_paths.py +1 -39
- package/docs/architecture/memory.md +20 -24
- package/docs/release-checklist.md +19 -6
- package/docs/usage.md +33 -17
- package/index.ts +8 -1
- package/ocmemog/__init__.py +11 -0
- package/ocmemog/doctor.py +1255 -0
- package/ocmemog/runtime/__init__.py +18 -0
- package/ocmemog/runtime/_compat_bridge.py +28 -0
- package/ocmemog/runtime/config.py +34 -0
- package/ocmemog/runtime/identity.py +115 -0
- package/ocmemog/runtime/inference.py +163 -0
- package/ocmemog/runtime/instrumentation.py +20 -0
- package/ocmemog/runtime/memory/__init__.py +91 -0
- package/ocmemog/runtime/memory/api.py +1594 -0
- package/ocmemog/runtime/memory/candidate.py +192 -0
- package/ocmemog/runtime/memory/conversation_state.py +1831 -0
- package/ocmemog/runtime/memory/distill.py +282 -0
- package/ocmemog/runtime/memory/embedding_engine.py +151 -0
- package/ocmemog/runtime/memory/freshness.py +114 -0
- package/ocmemog/runtime/memory/health.py +93 -0
- package/ocmemog/runtime/memory/integrity.py +208 -0
- package/ocmemog/runtime/memory/memory_consolidation.py +60 -0
- package/ocmemog/runtime/memory/memory_links.py +109 -0
- package/ocmemog/runtime/memory/memory_salience.py +235 -0
- package/ocmemog/runtime/memory/memory_synthesis.py +33 -0
- package/ocmemog/runtime/memory/memory_taxonomy.py +35 -0
- package/ocmemog/runtime/memory/pondering_engine.py +681 -0
- package/ocmemog/runtime/memory/promote.py +279 -0
- package/ocmemog/runtime/memory/provenance.py +408 -0
- package/ocmemog/runtime/memory/reinforcement.py +73 -0
- package/ocmemog/runtime/memory/retrieval.py +224 -0
- package/ocmemog/runtime/memory/semantic_search.py +66 -0
- package/ocmemog/runtime/memory/store.py +433 -0
- package/ocmemog/runtime/memory/unresolved_state.py +93 -0
- package/ocmemog/runtime/memory/vector_index.py +411 -0
- package/ocmemog/runtime/model_roles.py +15 -0
- package/ocmemog/runtime/model_router.py +28 -0
- package/ocmemog/runtime/providers.py +78 -0
- package/ocmemog/runtime/roles.py +92 -0
- package/ocmemog/runtime/security/__init__.py +8 -0
- package/ocmemog/runtime/security/redaction.py +17 -0
- package/ocmemog/runtime/state_store.py +32 -0
- package/ocmemog/runtime/storage_paths.py +70 -0
- package/ocmemog/sidecar/app.py +421 -60
- package/ocmemog/sidecar/compat.py +50 -13
- package/ocmemog/sidecar/transcript_watcher.py +327 -242
- package/openclaw.plugin.json +4 -0
- package/package.json +1 -1
- package/scripts/ocmemog-backfill-vectors.py +5 -3
- package/scripts/ocmemog-continuity-benchmark.py +1 -1
- package/scripts/ocmemog-demo.py +1 -1
- package/scripts/ocmemog-doctor.py +15 -0
- package/scripts/ocmemog-install.sh +29 -7
- package/scripts/ocmemog-integrated-proof.py +374 -0
- package/scripts/ocmemog-reindex-vectors.py +5 -3
- package/scripts/ocmemog-release-check.sh +330 -0
- package/scripts/ocmemog-sidecar.sh +4 -2
- package/scripts/ocmemog-test-rig.py +5 -3
- package/brain/runtime/memory/artifacts.py +0 -33
- package/brain/runtime/memory/context_builder.py +0 -112
- package/brain/runtime/memory/interaction_memory.py +0 -57
- package/brain/runtime/memory/memory_gate.py +0 -38
- package/brain/runtime/memory/memory_graph.py +0 -54
- package/brain/runtime/memory/person_identity.py +0 -83
- package/brain/runtime/memory/person_memory.py +0 -138
- package/brain/runtime/memory/sentiment_memory.py +0 -67
- package/brain/runtime/memory/tool_catalog.py +0 -68
|
@@ -1,187 +1,3 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
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
|