superlocalmemory 3.8.5 → 3.8.7
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 +47 -0
- package/README.md +3 -3
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/CLAUDE.md +3 -3
- package/plugin/agents/slm-governance-advisor.md +1 -1
- package/plugin/agents/slm-loop-runner.md +1 -1
- package/plugin/agents/slm-memory-advisor.md +1 -1
- package/plugin/agents/slm-optimize-advisor.md +1 -1
- package/plugin/requirements.txt +1 -1
- package/plugin/skills/slm-cache/SKILL.md +1 -1
- package/plugin/skills/slm-compress/SKILL.md +1 -1
- package/plugin/skills/slm-governance/SKILL.md +1 -1
- package/plugin/skills/slm-graph/SKILL.md +1 -1
- package/plugin/skills/slm-loop/SKILL.md +1 -1
- package/plugin/skills/slm-mesh/SKILL.md +1 -1
- package/plugin/skills/slm-profile/SKILL.md +1 -1
- package/plugin/skills/slm-recall/SKILL.md +1 -1
- package/plugin/skills/slm-remember/SKILL.md +1 -1
- package/plugin/skills/slm-scope/SKILL.md +1 -1
- package/plugin/skills/slm-session/SKILL.md +1 -1
- package/plugin/skills/slm-status/SKILL.md +1 -1
- package/plugin-src/rules/AGENTS.md +1 -1
- package/plugin-src/skills/slm-cache/SKILL.md +1 -1
- package/plugin-src/skills/slm-compress/SKILL.md +1 -1
- package/plugin-src/skills/slm-graph/SKILL.md +1 -1
- package/plugin-src/skills/slm-recall/SKILL.md +1 -1
- package/plugin-src/skills/slm-remember/SKILL.md +1 -1
- package/plugin-src/skills/slm-session/SKILL.md +1 -1
- package/plugin-src/skills/slm-status/SKILL.md +1 -1
- package/pyproject.toml +9 -1
- package/src/superlocalmemory/__init__.py +1 -1
- package/src/superlocalmemory/cli/commands.py +139 -404
- package/src/superlocalmemory/core/backend_orchestrator.py +7 -1
- package/src/superlocalmemory/core/component_registry.py +4 -2
- package/src/superlocalmemory/core/embeddings.py +33 -6
- package/src/superlocalmemory/core/engine.py +94 -49
- package/src/superlocalmemory/core/engine_ingestion.py +150 -63
- package/src/superlocalmemory/core/ingestion_command.py +133 -21
- package/src/superlocalmemory/core/mutations.py +32 -10
- package/src/superlocalmemory/core/recall_pipeline.py +111 -77
- package/src/superlocalmemory/core/remember_admission.py +152 -0
- package/src/superlocalmemory/core/remember_runtime.py +712 -0
- package/src/superlocalmemory/graph/cozo_backend.py +5 -5
- package/src/superlocalmemory/learning/bandit.py +50 -1
- package/src/superlocalmemory/learning/source_quality.py +38 -35
- package/src/superlocalmemory/mcp/_daemon_proxy.py +38 -15
- package/src/superlocalmemory/mcp/tools_active.py +4 -41
- package/src/superlocalmemory/mcp/tools_core.py +26 -87
- package/src/superlocalmemory/mcp/tools_evolution.py +5 -10
- package/src/superlocalmemory/optimize/proxy/capture.py +196 -8
- package/src/superlocalmemory/retrieval/engine.py +8 -3
- package/src/superlocalmemory/retrieval/reranker.py +35 -10
- package/src/superlocalmemory/server/loopback.py +7 -13
- package/src/superlocalmemory/server/profile_runtime.py +14 -0
- package/src/superlocalmemory/server/routes/abstraction.py +2 -4
- package/src/superlocalmemory/server/routes/agents.py +3 -5
- package/src/superlocalmemory/server/routes/behavioral.py +5 -13
- package/src/superlocalmemory/server/routes/brain.py +6 -9
- package/src/superlocalmemory/server/routes/entity.py +3 -7
- package/src/superlocalmemory/server/routes/evolution.py +3 -5
- package/src/superlocalmemory/server/routes/helpers.py +44 -23
- package/src/superlocalmemory/server/routes/insights.py +2 -4
- package/src/superlocalmemory/server/routes/learning.py +2 -5
- package/src/superlocalmemory/server/routes/lifecycle.py +2 -4
- package/src/superlocalmemory/server/routes/memories.py +122 -100
- package/src/superlocalmemory/server/routes/tiers.py +3 -22
- package/src/superlocalmemory/server/routes/timeline.py +2 -4
- package/src/superlocalmemory/server/routes/v3_api.py +18 -16
- package/src/superlocalmemory/server/unified_daemon.py +200 -109
- package/src/superlocalmemory/storage/admission_codec.py +119 -0
- package/src/superlocalmemory/storage/admission_journal.py +728 -0
- package/src/superlocalmemory/storage/database.py +59 -0
- package/src/superlocalmemory/storage/deferred_writes.py +67 -11
- package/src/superlocalmemory/storage/memory_write.py +8 -12
- package/src/superlocalmemory/storage/migration_runner.py +37 -0
- package/src/superlocalmemory/storage/migrations/M032_write_coordinator_admission.py +188 -0
- package/src/superlocalmemory/storage/read_connection.py +115 -0
- package/src/superlocalmemory/storage/write_coordinator.py +756 -0
- package/src/superlocalmemory/ui/index.html +1 -1
- package/src/superlocalmemory/ui/js/auto-settings.js +14 -1
- package/src/superlocalmemory/ui/js/od-settings.js +9 -3
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under AGPL-3.0-or-later - see LICENSE file
|
|
3
|
+
|
|
4
|
+
"""Journal-first service boundary for a durable, immediately-queryable remember."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import math
|
|
9
|
+
import time
|
|
10
|
+
from collections.abc import Mapping
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from typing import Any, Protocol
|
|
13
|
+
|
|
14
|
+
from superlocalmemory.storage.admission_journal import (
|
|
15
|
+
Actor,
|
|
16
|
+
AdmissionJournal,
|
|
17
|
+
AdmissionJournalUnavailable,
|
|
18
|
+
PreparedAdmission,
|
|
19
|
+
RememberRequest,
|
|
20
|
+
TerminalAdmissionError,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AdmissionRejected(RuntimeError):
|
|
25
|
+
"""Canonical admission was not committed; the journal records its outcome."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, error_code: str, *, retryable: bool = False) -> None:
|
|
28
|
+
super().__init__(error_code)
|
|
29
|
+
self.error_code = error_code
|
|
30
|
+
self.retryable = retryable
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True, slots=True)
|
|
34
|
+
class RememberReceipt:
|
|
35
|
+
"""Canonical receipt returned only after admission is queryable."""
|
|
36
|
+
|
|
37
|
+
payload: dict[str, Any]
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def from_mapping(cls, receipt: Mapping[str, Any]) -> RememberReceipt:
|
|
41
|
+
return cls(payload=dict(receipt))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass(frozen=True, slots=True)
|
|
45
|
+
class RememberAdmissionCommand:
|
|
46
|
+
"""Typed foreground input for a coordinator's bounded canonical transaction."""
|
|
47
|
+
|
|
48
|
+
journal_id: str
|
|
49
|
+
request_hash: str
|
|
50
|
+
request: RememberRequest
|
|
51
|
+
profile_id: str
|
|
52
|
+
idempotency_key: str
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def from_prepared(
|
|
56
|
+
cls, prepared: PreparedAdmission, request: RememberRequest
|
|
57
|
+
) -> RememberAdmissionCommand:
|
|
58
|
+
return cls(
|
|
59
|
+
journal_id=prepared.journal_id,
|
|
60
|
+
request_hash=prepared.request_hash,
|
|
61
|
+
request=request,
|
|
62
|
+
profile_id=prepared.profile_id,
|
|
63
|
+
idempotency_key=prepared.idempotency_key,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class RememberCoordinator(Protocol):
|
|
68
|
+
def submit(self, command: RememberAdmissionCommand, *, wait_ms: int) -> Any: ...
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class RememberService:
|
|
72
|
+
"""Apply the journaling pattern without doing enrichment inside admission."""
|
|
73
|
+
|
|
74
|
+
def __init__(self, journal: AdmissionJournal, coordinator: RememberCoordinator) -> None:
|
|
75
|
+
self._journal = journal
|
|
76
|
+
self._coordinator = coordinator
|
|
77
|
+
|
|
78
|
+
def remember(
|
|
79
|
+
self, request: RememberRequest, actor: Actor, *, deadline_ms: int
|
|
80
|
+
) -> RememberReceipt:
|
|
81
|
+
if deadline_ms <= 0:
|
|
82
|
+
raise ValueError("deadline_ms must be greater than zero")
|
|
83
|
+
deadline = time.monotonic() + deadline_ms / 1_000
|
|
84
|
+
prepared = self._journal.prepare(
|
|
85
|
+
request,
|
|
86
|
+
actor,
|
|
87
|
+
deadline=deadline,
|
|
88
|
+
)
|
|
89
|
+
if prepared.original_receipt is not None:
|
|
90
|
+
return RememberReceipt.from_mapping(prepared.original_receipt)
|
|
91
|
+
if prepared.state == "rejected":
|
|
92
|
+
raise AdmissionRejected(prepared.error_code or "COMMAND_REJECTED")
|
|
93
|
+
|
|
94
|
+
command_request = self._journal.request_for(
|
|
95
|
+
prepared,
|
|
96
|
+
deadline=deadline,
|
|
97
|
+
)
|
|
98
|
+
dispatched = self._journal.mark_dispatched(
|
|
99
|
+
prepared.journal_id,
|
|
100
|
+
deadline=deadline,
|
|
101
|
+
)
|
|
102
|
+
if dispatched.original_receipt is not None:
|
|
103
|
+
return RememberReceipt.from_mapping(dispatched.original_receipt)
|
|
104
|
+
try:
|
|
105
|
+
result = self._coordinator.submit(
|
|
106
|
+
RememberAdmissionCommand.from_prepared(prepared, command_request),
|
|
107
|
+
wait_ms=_remaining_milliseconds(deadline),
|
|
108
|
+
)
|
|
109
|
+
except TerminalAdmissionError as exc:
|
|
110
|
+
self._journal.mark_rejected(
|
|
111
|
+
prepared.journal_id,
|
|
112
|
+
exc.error_code,
|
|
113
|
+
deadline=deadline,
|
|
114
|
+
)
|
|
115
|
+
raise AdmissionRejected(exc.error_code) from exc
|
|
116
|
+
state = _result_value(result, "state")
|
|
117
|
+
receipt = _result_value(result, "receipt") or {}
|
|
118
|
+
if state in {"committed", "duplicate"}:
|
|
119
|
+
if not isinstance(receipt, Mapping):
|
|
120
|
+
raise AdmissionRejected("COMMAND_REJECTED: canonical result had no receipt")
|
|
121
|
+
committed = self._journal.mark_committed(
|
|
122
|
+
prepared.journal_id,
|
|
123
|
+
receipt,
|
|
124
|
+
deadline=deadline,
|
|
125
|
+
)
|
|
126
|
+
return RememberReceipt.from_mapping(committed.original_receipt or receipt)
|
|
127
|
+
|
|
128
|
+
error_code = str(_result_value(result, "error_code") or "COMMAND_REJECTED")
|
|
129
|
+
if state == "rejected":
|
|
130
|
+
self._journal.mark_rejected(
|
|
131
|
+
prepared.journal_id,
|
|
132
|
+
error_code,
|
|
133
|
+
deadline=deadline,
|
|
134
|
+
)
|
|
135
|
+
raise AdmissionRejected(error_code, retryable=state != "rejected")
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _result_value(result: Any, key: str) -> Any:
|
|
139
|
+
if isinstance(result, Mapping):
|
|
140
|
+
return result.get(key)
|
|
141
|
+
return getattr(result, key, None)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _remaining_seconds(deadline: float) -> float:
|
|
145
|
+
remaining = deadline - time.monotonic()
|
|
146
|
+
if remaining <= 0:
|
|
147
|
+
raise AdmissionJournalUnavailable("remember admission deadline expired")
|
|
148
|
+
return remaining
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _remaining_milliseconds(deadline: float) -> int:
|
|
152
|
+
return max(1, math.ceil(_remaining_seconds(deadline) * 1_000))
|