AbstractMemory 0.3.0__py3-none-any.whl → 0.3.2__py3-none-any.whl
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.
- abstractmemory/in_memory_store.py +23 -0
- abstractmemory/journal.py +14 -4
- abstractmemory/sqlite_store.py +35 -1
- abstractmemory/system.py +2 -1
- {abstractmemory-0.3.0.dist-info → abstractmemory-0.3.2.dist-info}/METADATA +3 -3
- {abstractmemory-0.3.0.dist-info → abstractmemory-0.3.2.dist-info}/RECORD +8 -8
- {abstractmemory-0.3.0.dist-info → abstractmemory-0.3.2.dist-info}/WHEEL +1 -1
- {abstractmemory-0.3.0.dist-info → abstractmemory-0.3.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import threading
|
|
4
4
|
import uuid
|
|
5
|
+
from dataclasses import replace
|
|
5
6
|
from typing import Any, Iterable, List, Optional, Sequence
|
|
6
7
|
|
|
7
8
|
from .embedding_pin import (
|
|
@@ -112,6 +113,28 @@ class InMemoryTripleStore:
|
|
|
112
113
|
self._embedder = embedder
|
|
113
114
|
return len(clean)
|
|
114
115
|
|
|
116
|
+
def close_assertion(self, assertion_id: str, valid_until: str) -> bool:
|
|
117
|
+
"""Close one assertion's validity window in place (SQLite parity):
|
|
118
|
+
sets `valid_until` only while it is still open; everything else is
|
|
119
|
+
untouched. True when a row changed; False for an unknown id or an
|
|
120
|
+
already-closed window."""
|
|
121
|
+
rid = str(assertion_id or "").strip()
|
|
122
|
+
until = str(valid_until or "").strip()
|
|
123
|
+
if not rid:
|
|
124
|
+
raise ValueError("close_assertion requires an assertion_id")
|
|
125
|
+
if not until:
|
|
126
|
+
raise ValueError("close_assertion requires a valid_until timestamp")
|
|
127
|
+
with self._lock:
|
|
128
|
+
for row in self._rows:
|
|
129
|
+
if row.get("assertion_id") != rid:
|
|
130
|
+
continue
|
|
131
|
+
a = row.get("assertion")
|
|
132
|
+
if not isinstance(a, TripleAssertion) or a.valid_until is not None:
|
|
133
|
+
return False
|
|
134
|
+
row["assertion"] = replace(a, valid_until=until)
|
|
135
|
+
return True
|
|
136
|
+
return False
|
|
137
|
+
|
|
115
138
|
def close(self) -> None:
|
|
116
139
|
return None
|
|
117
140
|
|
abstractmemory/journal.py
CHANGED
|
@@ -221,12 +221,22 @@ class ScopeBinding:
|
|
|
221
221
|
return _jsonify(asdict(self))
|
|
222
222
|
|
|
223
223
|
|
|
224
|
+
#: The closure kinds a ClosureRecord accepts (``reinterpreted`` is additive, 0.3.2).
|
|
225
|
+
CLOSURE_KINDS = frozenset({"retract", "supersede", "reinterpreted"})
|
|
226
|
+
|
|
227
|
+
|
|
224
228
|
@dataclass(frozen=True)
|
|
225
229
|
class ClosureRecord:
|
|
226
|
-
"""Append-only belief-lifecycle record (backlog 0010): retract or
|
|
230
|
+
"""Append-only belief-lifecycle record (backlog 0010): retract, supersede or reinterpreted.
|
|
231
|
+
|
|
232
|
+
``reinterpreted`` (additive, 0.3.2): the writer no longer reads its source this way (AbstractNote ADR 0008: a
|
|
233
|
+
note understood again against an earlier foundation withdraws its previous reading). It is neither a
|
|
234
|
+
correction of the fact (``retract``) nor a later fact replacing it (``supersede``); like both it leaves
|
|
235
|
+
ranked retrieval. ``replacement_ids`` is optional (the new reading's assertions, when there are any).
|
|
236
|
+
"""
|
|
227
237
|
|
|
228
238
|
assertion_id: str
|
|
229
|
-
kind: str # retract | supersede
|
|
239
|
+
kind: str # retract | supersede | reinterpreted
|
|
230
240
|
reason: str
|
|
231
241
|
replacement_ids: Tuple[str, ...] = ()
|
|
232
242
|
observed_at: str = field(default_factory=utc_now_iso)
|
|
@@ -240,8 +250,8 @@ class ClosureRecord:
|
|
|
240
250
|
raise ValueError("ClosureRecord requires assertion_id")
|
|
241
251
|
object.__setattr__(self, "assertion_id", self.assertion_id.strip())
|
|
242
252
|
kind = str(self.kind or "").strip().lower()
|
|
243
|
-
if kind not in
|
|
244
|
-
raise ValueError("ClosureRecord.kind must be 'retract' or '
|
|
253
|
+
if kind not in CLOSURE_KINDS:
|
|
254
|
+
raise ValueError("ClosureRecord.kind must be 'retract', 'supersede' or 'reinterpreted'")
|
|
245
255
|
object.__setattr__(self, "kind", kind)
|
|
246
256
|
if not (isinstance(self.reason, str) and self.reason.strip()):
|
|
247
257
|
raise ValueError("ClosureRecord requires a non-empty reason")
|
abstractmemory/sqlite_store.py
CHANGED
|
@@ -51,7 +51,8 @@ class SQLiteTripleStore:
|
|
|
51
51
|
|
|
52
52
|
Notes:
|
|
53
53
|
- Uses stdlib `sqlite3` (portable; no daemon).
|
|
54
|
-
- Append-only: there is no update/delete API (see AbstractMemory FAQ)
|
|
54
|
+
- Append-only: there is no update/delete API (see AbstractMemory FAQ),
|
|
55
|
+
except `close_assertion`, which only closes an open validity window.
|
|
55
56
|
- VECTORS (a2a 0003, the entity-home pairing): pass `embedder=` and each
|
|
56
57
|
added assertion's canonical text is embedded and persisted in the SAME
|
|
57
58
|
.sqlite3 file (JSON-encoded `embedding` column; in-place ALTER TABLE
|
|
@@ -526,6 +527,39 @@ class SQLiteTripleStore:
|
|
|
526
527
|
rows = self._conn.cursor().execute(sql, params).fetchall()
|
|
527
528
|
return [self._row_to_assertion(r) for r in rows]
|
|
528
529
|
|
|
530
|
+
def close_assertion(self, assertion_id: str, valid_until: str) -> bool:
|
|
531
|
+
"""Close one assertion's validity window IN PLACE (additive, backlog:
|
|
532
|
+
abstractnote supersession). Sets `valid_until` only while it is still
|
|
533
|
+
open (NULL); every other column — terms, provenance, attributes, the
|
|
534
|
+
FTS row, the vector — is untouched, so the store stays append-only
|
|
535
|
+
for content. Returns True when a row changed, False when the id is
|
|
536
|
+
unknown or the window was already closed (idempotent replays).
|
|
537
|
+
|
|
538
|
+
Why: a later fact superseding an earlier one must make
|
|
539
|
+
`TripleQuery(active_at=...)` agree with the writer's belief window;
|
|
540
|
+
journal closures alone only reach ranked retrieval, never `query`."""
|
|
541
|
+
rid = str(assertion_id or "").strip()
|
|
542
|
+
until = str(valid_until or "").strip()
|
|
543
|
+
if not rid:
|
|
544
|
+
raise ValueError("close_assertion requires an assertion_id")
|
|
545
|
+
if not until:
|
|
546
|
+
raise ValueError("close_assertion requires a valid_until timestamp")
|
|
547
|
+
with self._lock:
|
|
548
|
+
cur = self._conn.cursor()
|
|
549
|
+
cur.execute("BEGIN IMMEDIATE")
|
|
550
|
+
try:
|
|
551
|
+
cur.execute(
|
|
552
|
+
f"UPDATE {self._table} SET valid_until = ? "
|
|
553
|
+
"WHERE assertion_id = ? AND valid_until IS NULL",
|
|
554
|
+
(until, rid),
|
|
555
|
+
)
|
|
556
|
+
changed = int(cur.rowcount or 0) > 0
|
|
557
|
+
cur.execute("COMMIT")
|
|
558
|
+
except BaseException:
|
|
559
|
+
cur.execute("ROLLBACK")
|
|
560
|
+
raise
|
|
561
|
+
return changed
|
|
562
|
+
|
|
529
563
|
def replace_vectors(
|
|
530
564
|
self, vectors: dict, pin: dict, *,
|
|
531
565
|
expected_row_count: int, embedder: Optional[TextEmbedder] = None,
|
abstractmemory/system.py
CHANGED
|
@@ -853,7 +853,8 @@ class MemorySystem(ValenceOps, AccessOps):
|
|
|
853
853
|
replacement_ids: Sequence[str] = (),
|
|
854
854
|
reason: str,
|
|
855
855
|
) -> List[str]:
|
|
856
|
-
"""Append one ClosureRecord per assertion (retract | supersede
|
|
856
|
+
"""Append one ClosureRecord per assertion (retract | supersede |
|
|
857
|
+
reinterpreted);
|
|
857
858
|
returns closure ids. Supersede requires replacement_ids; reason is
|
|
858
859
|
mandatory — validated by ClosureRecord BEFORE any append. A multi-
|
|
859
860
|
assertion supersede shares one replacement set. Accepts either id
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: AbstractMemory
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: AbstractMemory: temporal, provenance-aware semantic memory primitives for AbstractFramework.
|
|
5
5
|
Project-URL: AbstractFramework (monorepo), https://github.com/lpalbou/abstractframework
|
|
6
6
|
Author: Laurent-Philippe Albou
|
|
@@ -164,7 +164,7 @@ system.commit_selection(result.trace_id, [h.record_id for h in result.handles[:2
|
|
|
164
164
|
|
|
165
165
|
## Design principles
|
|
166
166
|
|
|
167
|
-
- **Append-only, no deletion**: updates are new assertions; belief revision is closure records (retract/supersede); forgetting is decay of retrieval strength plus closures and silencing — the substrate is lossless.
|
|
167
|
+
- **Append-only, no deletion**: updates are new assertions; belief revision is closure records (retract/supersede/reinterpreted); forgetting is decay of retrieval strength plus closures and silencing — the substrate is lossless.
|
|
168
168
|
- **Reads are pure**: reconstruction, inspection, replay, and the entity card deposit nothing. `commit_selection` is the only strengthening path.
|
|
169
169
|
- **One seq axis**: the journal assigns a monotonic `seq` to every record; any past state is reproducible by anchoring reads at `as_of`.
|
|
170
170
|
- **Works-or-loud**: degraded paths are labeled `#FALLBACK` in result warnings; invalid inputs raise actionable errors instead of silently meaning something else.
|
|
@@ -25,8 +25,8 @@ abstractmemory/feelings_reads.py,sha256=eCnLLEnJwOw6NvWss2P4OXpitsDMieyPT5loDfiI
|
|
|
25
25
|
abstractmemory/folds.py,sha256=DPy8po7k0Hp8HdEwbXwsS376mCYiECPk1-Ct2l_CNJg,17004
|
|
26
26
|
abstractmemory/gradation.py,sha256=iee4w4hoEmGw72BN7XeoWru2-AF3viPsCrAY_8k3sVk,11850
|
|
27
27
|
abstractmemory/identity_review.py,sha256=6PajkCICR4JXiG53T2EeNQuJitMnefxLni2x0zI6Ai8,7434
|
|
28
|
-
abstractmemory/in_memory_store.py,sha256=
|
|
29
|
-
abstractmemory/journal.py,sha256=
|
|
28
|
+
abstractmemory/in_memory_store.py,sha256=hbJhfQonNYXI3ywLbuFU9XRNHuxG0fb3PXWrYeDVR58,13241
|
|
29
|
+
abstractmemory/journal.py,sha256=Xe6vxGFfkuN-8wkWOX9vF_spr9q41jUu5I9Wo4Bv-Rg,24157
|
|
30
30
|
abstractmemory/journal_common.py,sha256=nB9jnUKFe-TTtc1YD5__kZTuqH56K5-A2oxaWNaIO34,9303
|
|
31
31
|
abstractmemory/journal_memory.py,sha256=fHMSSw8CLfKPMMaI6yIoyxjpN6h_reqPI6ILuptngU0,23611
|
|
32
32
|
abstractmemory/journal_sqlite.py,sha256=7Te1Lsh2d-Em9IMVUELcJa-flaqWRAQUBX994hAie20,28480
|
|
@@ -54,9 +54,9 @@ abstractmemory/sleep_cadence.py,sha256=sESud9WayZbPCzDO9Yfu8PWgVyyu3LtA0bTovTRzj
|
|
|
54
54
|
abstractmemory/sleep_policy.py,sha256=xZftQLMJq6Rn9mEHc6N4BwLypmDtAKwWAXG7o-kPC_s,7471
|
|
55
55
|
abstractmemory/spark.py,sha256=9Pmof_9TKHNkts-yMekOMV3Z-RrbQxEEwN56MK73iUE,8833
|
|
56
56
|
abstractmemory/spreading.py,sha256=22-UZCuLrQ9w-2YbsOrTAR5pQOgopSJv9qbYeWGn3uE,16031
|
|
57
|
-
abstractmemory/sqlite_store.py,sha256=
|
|
57
|
+
abstractmemory/sqlite_store.py,sha256=Fz2ChaUfJ-OrCELpJrdgK9z2BS605Gao-stpKMv58_I,32527
|
|
58
58
|
abstractmemory/store.py,sha256=4PXG-4JsNaBojr39CkrmR6fKRT9McRHK-bKXqB0eHaY,4195
|
|
59
|
-
abstractmemory/system.py,sha256=
|
|
59
|
+
abstractmemory/system.py,sha256=jox7PPMmg9XV7TZXO9Wh1l_A78sYUmLRSLbV_AL1Bug,47384
|
|
60
60
|
abstractmemory/system_access.py,sha256=cwj6fTyyApzWtaZiQbI72gbh03650rc4SxlePr-MwLY,6696
|
|
61
61
|
abstractmemory/system_valence.py,sha256=JqX2W0GHkuzxkyl0QoJt7r24EEk8LIPAeN8eZNPUwqk,11627
|
|
62
62
|
abstractmemory/tend.py,sha256=ubOh-Bb01Ro0B3WCNvdfquO-qExoF06_uo8RKPAq4HM,30080
|
|
@@ -64,7 +64,7 @@ abstractmemory/text_tokens.py,sha256=kYWAdNEEnGi50zuCam3bA6VY91An0C_6HlDlxqwkun8
|
|
|
64
64
|
abstractmemory/vector_scoring.py,sha256=1NlC8DdoN0VFv5z6r2wyURvs86p6kbCJsKg4f__FEtw,2511
|
|
65
65
|
abstractmemory/world_model.py,sha256=aHlRyyXz8hQOTbjtXzJpUpFy01wjkShyyUviAs4ST0w,46714
|
|
66
66
|
abstractmemory/world_model_alias.py,sha256=A4_or9kmhgCu6AdxaZQEJQQsPi0RG9ZsePdBG9_JYnM,9436
|
|
67
|
-
abstractmemory-0.3.
|
|
68
|
-
abstractmemory-0.3.
|
|
69
|
-
abstractmemory-0.3.
|
|
70
|
-
abstractmemory-0.3.
|
|
67
|
+
abstractmemory-0.3.2.dist-info/METADATA,sha256=TY3BUpPbVdVcKkda9Uyc5eVvQfDzZChMUVCmdf2hpVY,7506
|
|
68
|
+
abstractmemory-0.3.2.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
69
|
+
abstractmemory-0.3.2.dist-info/licenses/LICENSE,sha256=7t9ARuV3s_QVhJahnkFBnX_E5GPLW8BE9geplO1CGko,1079
|
|
70
|
+
abstractmemory-0.3.2.dist-info/RECORD,,
|
|
File without changes
|