cognitive-memory 0.2.0__tar.gz
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.
- cognitive_memory-0.2.0/.gitignore +55 -0
- cognitive_memory-0.2.0/PKG-INFO +46 -0
- cognitive_memory-0.2.0/README.md +5 -0
- cognitive_memory-0.2.0/pyproject.toml +58 -0
- cognitive_memory-0.2.0/src/cognitive_memory/__init__.py +70 -0
- cognitive_memory-0.2.0/src/cognitive_memory/_sync.py +135 -0
- cognitive_memory-0.2.0/src/cognitive_memory/adapters/__init__.py +9 -0
- cognitive_memory-0.2.0/src/cognitive_memory/adapters/base.py +235 -0
- cognitive_memory-0.2.0/src/cognitive_memory/adapters/convex.py +13 -0
- cognitive_memory-0.2.0/src/cognitive_memory/adapters/jsonl.py +13 -0
- cognitive_memory-0.2.0/src/cognitive_memory/adapters/memory.py +338 -0
- cognitive_memory-0.2.0/src/cognitive_memory/adapters/postgres.py +12 -0
- cognitive_memory-0.2.0/src/cognitive_memory/adapters/redis.py +12 -0
- cognitive_memory-0.2.0/src/cognitive_memory/adapters/sqlite.py +12 -0
- cognitive_memory-0.2.0/src/cognitive_memory/core.py +374 -0
- cognitive_memory-0.2.0/src/cognitive_memory/embeddings.py +107 -0
- cognitive_memory-0.2.0/src/cognitive_memory/engine.py +781 -0
- cognitive_memory-0.2.0/src/cognitive_memory/extraction.py +369 -0
- cognitive_memory-0.2.0/src/cognitive_memory/py.typed +0 -0
- cognitive_memory-0.2.0/src/cognitive_memory/store.py +10 -0
- cognitive_memory-0.2.0/src/cognitive_memory/types.py +216 -0
- cognitive_memory-0.2.0/tests/__init__.py +0 -0
- cognitive_memory-0.2.0/tests/test_adapters/__init__.py +0 -0
- cognitive_memory-0.2.0/tests/test_adapters/conftest.py +18 -0
- cognitive_memory-0.2.0/tests/test_adapters/test_conformance.py +104 -0
- cognitive_memory-0.2.0/tests/test_sdk.py +399 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
.pnp/
|
|
4
|
+
.pnp.js
|
|
5
|
+
|
|
6
|
+
# Python
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
__pycache__/
|
|
10
|
+
*.pyc
|
|
11
|
+
*.pyo
|
|
12
|
+
*.egg-info/
|
|
13
|
+
dist/
|
|
14
|
+
build/
|
|
15
|
+
*.egg
|
|
16
|
+
.eggs/
|
|
17
|
+
|
|
18
|
+
# TypeScript / Node build
|
|
19
|
+
dist/
|
|
20
|
+
*.tsbuildinfo
|
|
21
|
+
|
|
22
|
+
# Environment
|
|
23
|
+
.env
|
|
24
|
+
.env.local
|
|
25
|
+
.env.*.local
|
|
26
|
+
|
|
27
|
+
# Coverage
|
|
28
|
+
coverage/
|
|
29
|
+
htmlcov/
|
|
30
|
+
.coverage
|
|
31
|
+
.nyc_output/
|
|
32
|
+
|
|
33
|
+
# IDE
|
|
34
|
+
.vscode/
|
|
35
|
+
.idea/
|
|
36
|
+
*.swp
|
|
37
|
+
*.swo
|
|
38
|
+
*~
|
|
39
|
+
|
|
40
|
+
# OS
|
|
41
|
+
.DS_Store
|
|
42
|
+
Thumbs.db
|
|
43
|
+
|
|
44
|
+
# Docs build
|
|
45
|
+
docs/dist/
|
|
46
|
+
docs/.astro/
|
|
47
|
+
|
|
48
|
+
# Test artifacts
|
|
49
|
+
.pytest_cache/
|
|
50
|
+
.mypy_cache/
|
|
51
|
+
.ruff_cache/
|
|
52
|
+
|
|
53
|
+
# Lockfiles (keep package-lock.json)
|
|
54
|
+
!package-lock.json
|
|
55
|
+
.vercel
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cognitive-memory
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Biologically-inspired agent memory with decay, consolidation, and tiered storage
|
|
5
|
+
Project-URL: Homepage, https://github.com/bhekanik/cognitive-memory
|
|
6
|
+
Project-URL: Documentation, https://bhekanik.github.io/cognitive-memory
|
|
7
|
+
Project-URL: Repository, https://github.com/bhekanik/cognitive-memory
|
|
8
|
+
Project-URL: Issues, https://github.com/bhekanik/cognitive-memory/issues
|
|
9
|
+
Author: Bhekani Khumalo
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
Keywords: agents,ai,cognitive,decay,llm,memory
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: numpy>=1.24
|
|
23
|
+
Provides-Extra: all
|
|
24
|
+
Requires-Dist: aiosqlite>=0.19; extra == 'all'
|
|
25
|
+
Requires-Dist: asyncpg>=0.29; extra == 'all'
|
|
26
|
+
Requires-Dist: openai>=1.0; extra == 'all'
|
|
27
|
+
Requires-Dist: redis[hiredis]>=5.0; extra == 'all'
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
32
|
+
Provides-Extra: openai
|
|
33
|
+
Requires-Dist: openai>=1.0; extra == 'openai'
|
|
34
|
+
Provides-Extra: postgres
|
|
35
|
+
Requires-Dist: asyncpg>=0.29; extra == 'postgres'
|
|
36
|
+
Provides-Extra: redis
|
|
37
|
+
Requires-Dist: redis[hiredis]>=5.0; extra == 'redis'
|
|
38
|
+
Provides-Extra: sqlite
|
|
39
|
+
Requires-Dist: aiosqlite>=0.19; extra == 'sqlite'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
# cognitive-memory (Python)
|
|
43
|
+
|
|
44
|
+
Biologically-inspired agent memory with decay, consolidation, and tiered storage.
|
|
45
|
+
|
|
46
|
+
See [documentation](https://bhekanik.github.io/cognitive-memory) for details.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cognitive-memory"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "Biologically-inspired agent memory with decay, consolidation, and tiered storage"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Bhekani Khumalo" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["memory", "ai", "agents", "cognitive", "decay", "llm"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"numpy>=1.24",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
openai = ["openai>=1.0"]
|
|
33
|
+
sqlite = ["aiosqlite>=0.19"]
|
|
34
|
+
postgres = ["asyncpg>=0.29"]
|
|
35
|
+
redis = ["redis[hiredis]>=5.0"]
|
|
36
|
+
all = ["cognitive-memory[openai,sqlite,postgres,redis]"]
|
|
37
|
+
dev = [
|
|
38
|
+
"pytest>=7.0",
|
|
39
|
+
"pytest-asyncio>=0.23",
|
|
40
|
+
"ruff>=0.4",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[project.urls]
|
|
44
|
+
Homepage = "https://github.com/bhekanik/cognitive-memory"
|
|
45
|
+
Documentation = "https://bhekanik.github.io/cognitive-memory"
|
|
46
|
+
Repository = "https://github.com/bhekanik/cognitive-memory"
|
|
47
|
+
Issues = "https://github.com/bhekanik/cognitive-memory/issues"
|
|
48
|
+
|
|
49
|
+
[tool.hatch.build.targets.wheel]
|
|
50
|
+
packages = ["src/cognitive_memory"]
|
|
51
|
+
|
|
52
|
+
[tool.pytest.ini_options]
|
|
53
|
+
testpaths = ["tests"]
|
|
54
|
+
asyncio_mode = "auto"
|
|
55
|
+
|
|
56
|
+
[tool.ruff]
|
|
57
|
+
target-version = "py310"
|
|
58
|
+
line-length = 120
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
cognitive-memory: A Python SDK for biologically-inspired agent memory.
|
|
3
|
+
|
|
4
|
+
Implements decay floors, emergent core memory detection, two-tier
|
|
5
|
+
retrieval boosting, associative linking, tiered hot/cold storage
|
|
6
|
+
with TTL, and reversible consolidation.
|
|
7
|
+
|
|
8
|
+
Quick start:
|
|
9
|
+
from cognitive_memory import SyncCognitiveMemory
|
|
10
|
+
|
|
11
|
+
mem = SyncCognitiveMemory(embedder="hash")
|
|
12
|
+
mem.add("User is allergic to shellfish", category="core", importance=0.95)
|
|
13
|
+
results = mem.search("what allergies does the user have?")
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from .core import CognitiveMemory
|
|
17
|
+
from ._sync import SyncCognitiveMemory
|
|
18
|
+
from .types import (
|
|
19
|
+
Memory,
|
|
20
|
+
MemoryCategory,
|
|
21
|
+
CognitiveMemoryConfig,
|
|
22
|
+
SearchResult,
|
|
23
|
+
SearchResponse,
|
|
24
|
+
SearchTrace,
|
|
25
|
+
StageTrace,
|
|
26
|
+
Association,
|
|
27
|
+
)
|
|
28
|
+
from .engine import CognitiveEngine
|
|
29
|
+
from .extraction import MemoryExtractor
|
|
30
|
+
from .embeddings import (
|
|
31
|
+
EmbeddingProvider,
|
|
32
|
+
OpenAIEmbeddings,
|
|
33
|
+
HashEmbeddings,
|
|
34
|
+
cosine_similarity,
|
|
35
|
+
)
|
|
36
|
+
from .adapters import MemoryAdapter, InMemoryAdapter
|
|
37
|
+
|
|
38
|
+
# Backward compat
|
|
39
|
+
from .store import MemoryStore
|
|
40
|
+
|
|
41
|
+
__version__ = "0.1.0"
|
|
42
|
+
|
|
43
|
+
__all__ = [
|
|
44
|
+
# Main API
|
|
45
|
+
"CognitiveMemory",
|
|
46
|
+
"SyncCognitiveMemory",
|
|
47
|
+
# Types
|
|
48
|
+
"CognitiveMemoryConfig",
|
|
49
|
+
"Memory",
|
|
50
|
+
"MemoryCategory",
|
|
51
|
+
"SearchResult",
|
|
52
|
+
"SearchResponse",
|
|
53
|
+
"SearchTrace",
|
|
54
|
+
"StageTrace",
|
|
55
|
+
"Association",
|
|
56
|
+
# Engine
|
|
57
|
+
"CognitiveEngine",
|
|
58
|
+
# Extraction
|
|
59
|
+
"MemoryExtractor",
|
|
60
|
+
# Embeddings
|
|
61
|
+
"EmbeddingProvider",
|
|
62
|
+
"OpenAIEmbeddings",
|
|
63
|
+
"HashEmbeddings",
|
|
64
|
+
"cosine_similarity",
|
|
65
|
+
# Adapters
|
|
66
|
+
"MemoryAdapter",
|
|
67
|
+
"InMemoryAdapter",
|
|
68
|
+
# Backward compat
|
|
69
|
+
"MemoryStore",
|
|
70
|
+
]
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Synchronous wrapper around async CognitiveMemory.
|
|
3
|
+
|
|
4
|
+
Provides the same API but runs everything through asyncio.run().
|
|
5
|
+
Useful for scripts, notebooks, and benchmark compatibility.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from typing import Optional, Literal
|
|
13
|
+
|
|
14
|
+
from .types import Memory, MemoryCategory, CognitiveMemoryConfig, SearchResult, SearchResponse
|
|
15
|
+
from .adapters.base import MemoryAdapter
|
|
16
|
+
from .embeddings import EmbeddingProvider
|
|
17
|
+
from .core import CognitiveMemory
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _run(coro):
|
|
21
|
+
"""Run an async coroutine synchronously."""
|
|
22
|
+
try:
|
|
23
|
+
loop = asyncio.get_running_loop()
|
|
24
|
+
except RuntimeError:
|
|
25
|
+
loop = None
|
|
26
|
+
|
|
27
|
+
if loop and loop.is_running():
|
|
28
|
+
# We're inside an existing event loop (e.g., Jupyter).
|
|
29
|
+
# Create a new loop in a thread.
|
|
30
|
+
import concurrent.futures
|
|
31
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool:
|
|
32
|
+
return pool.submit(asyncio.run, coro).result()
|
|
33
|
+
else:
|
|
34
|
+
return asyncio.run(coro)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class SyncCognitiveMemory:
|
|
38
|
+
"""
|
|
39
|
+
Synchronous wrapper around CognitiveMemory.
|
|
40
|
+
|
|
41
|
+
Usage:
|
|
42
|
+
from cognitive_memory import SyncCognitiveMemory
|
|
43
|
+
|
|
44
|
+
mem = SyncCognitiveMemory(embedder="hash")
|
|
45
|
+
mem.add("User likes coffee", importance=0.5)
|
|
46
|
+
results = mem.search("coffee")
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
config: Optional[CognitiveMemoryConfig] = None,
|
|
52
|
+
embedder: Optional[EmbeddingProvider | Literal["openai", "hash"]] = None,
|
|
53
|
+
adapter: Optional[MemoryAdapter] = None,
|
|
54
|
+
):
|
|
55
|
+
self._async = CognitiveMemory(
|
|
56
|
+
config=config,
|
|
57
|
+
embedder=embedder,
|
|
58
|
+
adapter=adapter,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def add(
|
|
62
|
+
self,
|
|
63
|
+
content: str,
|
|
64
|
+
category: MemoryCategory = MemoryCategory.EPISODIC,
|
|
65
|
+
importance: float = 0.5,
|
|
66
|
+
session_id: Optional[str] = None,
|
|
67
|
+
timestamp: Optional[datetime] = None,
|
|
68
|
+
) -> Memory:
|
|
69
|
+
return _run(self._async.add(
|
|
70
|
+
content=content,
|
|
71
|
+
category=category,
|
|
72
|
+
importance=importance,
|
|
73
|
+
session_id=session_id,
|
|
74
|
+
timestamp=timestamp,
|
|
75
|
+
))
|
|
76
|
+
|
|
77
|
+
def add_memory_object(self, memory: Memory) -> Memory:
|
|
78
|
+
return _run(self._async.add_memory_object(memory))
|
|
79
|
+
|
|
80
|
+
def extract_and_store(
|
|
81
|
+
self,
|
|
82
|
+
conversation_text: str,
|
|
83
|
+
session_id: str,
|
|
84
|
+
timestamp: Optional[datetime] = None,
|
|
85
|
+
run_tick: bool = True,
|
|
86
|
+
) -> list[Memory]:
|
|
87
|
+
return _run(self._async.extract_and_store(
|
|
88
|
+
conversation_text=conversation_text,
|
|
89
|
+
session_id=session_id,
|
|
90
|
+
timestamp=timestamp,
|
|
91
|
+
run_tick=run_tick,
|
|
92
|
+
))
|
|
93
|
+
|
|
94
|
+
def search(
|
|
95
|
+
self,
|
|
96
|
+
query: str,
|
|
97
|
+
top_k: int = 10,
|
|
98
|
+
timestamp: Optional[datetime] = None,
|
|
99
|
+
session_id: Optional[str] = None,
|
|
100
|
+
deep_recall: bool = False,
|
|
101
|
+
trace: bool = False,
|
|
102
|
+
) -> SearchResponse:
|
|
103
|
+
return _run(self._async.search(
|
|
104
|
+
query=query,
|
|
105
|
+
top_k=top_k,
|
|
106
|
+
timestamp=timestamp,
|
|
107
|
+
session_id=session_id,
|
|
108
|
+
deep_recall=deep_recall,
|
|
109
|
+
trace=trace,
|
|
110
|
+
))
|
|
111
|
+
|
|
112
|
+
def tick(self, now: Optional[datetime] = None):
|
|
113
|
+
return _run(self._async.tick(now))
|
|
114
|
+
|
|
115
|
+
def get_stats(self) -> dict:
|
|
116
|
+
return _run(self._async.get_stats())
|
|
117
|
+
|
|
118
|
+
def clear(self):
|
|
119
|
+
return _run(self._async.clear())
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def adapter(self) -> MemoryAdapter:
|
|
123
|
+
return self._async.adapter
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def engine(self):
|
|
127
|
+
return self._async.engine
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def embedder(self) -> EmbeddingProvider:
|
|
131
|
+
return self._async.embedder
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def config(self) -> CognitiveMemoryConfig:
|
|
135
|
+
return self._async.config
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Abstract base class for memory storage adapters.
|
|
3
|
+
|
|
4
|
+
All adapters are async-first. Use SyncCognitiveMemory for sync wrappers.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from abc import ABC, abstractmethod
|
|
10
|
+
from typing import Optional, Callable, TypeVar
|
|
11
|
+
|
|
12
|
+
from ..types import Memory
|
|
13
|
+
|
|
14
|
+
T = TypeVar("T")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MemoryAdapter(ABC):
|
|
18
|
+
"""
|
|
19
|
+
Abstract adapter interface for cognitive-memory storage backends.
|
|
20
|
+
|
|
21
|
+
Implementations must provide async methods for CRUD, vector search,
|
|
22
|
+
tiered storage migration, associative links, and consolidation.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
# ------------------------------------------------------------------
|
|
26
|
+
# CRUD
|
|
27
|
+
# ------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
async def create(self, memory: Memory) -> None:
|
|
31
|
+
"""Store a new memory."""
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
async def get(self, memory_id: str) -> Optional[Memory]:
|
|
36
|
+
"""Get a memory by ID from any tier."""
|
|
37
|
+
...
|
|
38
|
+
|
|
39
|
+
@abstractmethod
|
|
40
|
+
async def get_batch(self, memory_ids: list[str]) -> list[Memory]:
|
|
41
|
+
"""Get multiple memories by ID."""
|
|
42
|
+
...
|
|
43
|
+
|
|
44
|
+
@abstractmethod
|
|
45
|
+
async def update(self, memory: Memory) -> None:
|
|
46
|
+
"""Update an existing memory in place."""
|
|
47
|
+
...
|
|
48
|
+
|
|
49
|
+
@abstractmethod
|
|
50
|
+
async def delete(self, memory_id: str) -> None:
|
|
51
|
+
"""Hard delete from any tier."""
|
|
52
|
+
...
|
|
53
|
+
|
|
54
|
+
@abstractmethod
|
|
55
|
+
async def delete_batch(self, memory_ids: list[str]) -> None:
|
|
56
|
+
"""Hard delete multiple memories."""
|
|
57
|
+
...
|
|
58
|
+
|
|
59
|
+
# ------------------------------------------------------------------
|
|
60
|
+
# Vector search
|
|
61
|
+
# ------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
@abstractmethod
|
|
64
|
+
async def search_similar(
|
|
65
|
+
self,
|
|
66
|
+
query_embedding: list[float],
|
|
67
|
+
top_k: int = 10,
|
|
68
|
+
include_superseded: bool = False,
|
|
69
|
+
) -> list[tuple[Memory, float]]:
|
|
70
|
+
"""
|
|
71
|
+
Search by cosine similarity.
|
|
72
|
+
|
|
73
|
+
Returns list of (memory, similarity_score) sorted descending.
|
|
74
|
+
Superseded memories are excluded by default.
|
|
75
|
+
"""
|
|
76
|
+
...
|
|
77
|
+
|
|
78
|
+
# ------------------------------------------------------------------
|
|
79
|
+
# Lexical search (optional, for hybrid retrieval)
|
|
80
|
+
# ------------------------------------------------------------------
|
|
81
|
+
|
|
82
|
+
async def search_lexical(
|
|
83
|
+
self,
|
|
84
|
+
query: str,
|
|
85
|
+
top_k: int = 10,
|
|
86
|
+
include_superseded: bool = False,
|
|
87
|
+
) -> list[tuple["Memory", float]]:
|
|
88
|
+
"""
|
|
89
|
+
BM25/lexical search. Override in adapters that support it.
|
|
90
|
+
Returns list of (memory, bm25_score) sorted descending.
|
|
91
|
+
Default: returns empty list (dense-only fallback).
|
|
92
|
+
"""
|
|
93
|
+
return []
|
|
94
|
+
|
|
95
|
+
# ------------------------------------------------------------------
|
|
96
|
+
# Tiered storage
|
|
97
|
+
# ------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
@abstractmethod
|
|
100
|
+
async def migrate_to_cold(self, memory_id: str, cold_since: "datetime") -> None:
|
|
101
|
+
"""Move a memory from hot to cold store."""
|
|
102
|
+
...
|
|
103
|
+
|
|
104
|
+
@abstractmethod
|
|
105
|
+
async def migrate_to_hot(self, memory_id: str) -> None:
|
|
106
|
+
"""Reactivate a cold memory back to hot store."""
|
|
107
|
+
...
|
|
108
|
+
|
|
109
|
+
@abstractmethod
|
|
110
|
+
async def convert_to_stub(self, memory_id: str, stub_content: str) -> None:
|
|
111
|
+
"""Replace a memory with a lightweight stub (TTL expiry)."""
|
|
112
|
+
...
|
|
113
|
+
|
|
114
|
+
# ------------------------------------------------------------------
|
|
115
|
+
# Associative links
|
|
116
|
+
# ------------------------------------------------------------------
|
|
117
|
+
|
|
118
|
+
@abstractmethod
|
|
119
|
+
async def create_or_strengthen_link(
|
|
120
|
+
self, source_id: str, target_id: str, weight: float,
|
|
121
|
+
) -> None:
|
|
122
|
+
"""Create or strengthen a bidirectional association."""
|
|
123
|
+
...
|
|
124
|
+
|
|
125
|
+
@abstractmethod
|
|
126
|
+
async def get_linked_memories(
|
|
127
|
+
self, memory_id: str, min_weight: float = 0.3,
|
|
128
|
+
) -> list[tuple[Memory, float]]:
|
|
129
|
+
"""Get memories linked to a given memory above threshold."""
|
|
130
|
+
...
|
|
131
|
+
|
|
132
|
+
@abstractmethod
|
|
133
|
+
async def delete_link(self, source_id: str, target_id: str) -> None:
|
|
134
|
+
"""Delete an association between two memories."""
|
|
135
|
+
...
|
|
136
|
+
|
|
137
|
+
# ------------------------------------------------------------------
|
|
138
|
+
# Consolidation helpers
|
|
139
|
+
# ------------------------------------------------------------------
|
|
140
|
+
|
|
141
|
+
@abstractmethod
|
|
142
|
+
async def find_fading(
|
|
143
|
+
self, threshold: float, exclude_core: bool = True,
|
|
144
|
+
) -> list[Memory]:
|
|
145
|
+
"""Find non-superseded memories with retention below threshold."""
|
|
146
|
+
...
|
|
147
|
+
|
|
148
|
+
@abstractmethod
|
|
149
|
+
async def find_stable(
|
|
150
|
+
self, min_stability: float, min_access_count: int,
|
|
151
|
+
) -> list[Memory]:
|
|
152
|
+
"""Find highly stable, frequently accessed memories."""
|
|
153
|
+
...
|
|
154
|
+
|
|
155
|
+
@abstractmethod
|
|
156
|
+
async def mark_superseded(
|
|
157
|
+
self, memory_ids: list[str], summary_id: str,
|
|
158
|
+
) -> None:
|
|
159
|
+
"""Mark memories as superseded by a consolidation summary."""
|
|
160
|
+
...
|
|
161
|
+
|
|
162
|
+
# ------------------------------------------------------------------
|
|
163
|
+
# Traversal
|
|
164
|
+
# ------------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
@abstractmethod
|
|
167
|
+
async def all_active(self) -> list[Memory]:
|
|
168
|
+
"""All memories in hot + cold (not stubs)."""
|
|
169
|
+
...
|
|
170
|
+
|
|
171
|
+
@abstractmethod
|
|
172
|
+
async def all_hot(self) -> list[Memory]:
|
|
173
|
+
"""All memories in the hot store."""
|
|
174
|
+
...
|
|
175
|
+
|
|
176
|
+
@abstractmethod
|
|
177
|
+
async def all_cold(self) -> list[Memory]:
|
|
178
|
+
"""All memories in the cold store."""
|
|
179
|
+
...
|
|
180
|
+
|
|
181
|
+
# ------------------------------------------------------------------
|
|
182
|
+
# Counts
|
|
183
|
+
# ------------------------------------------------------------------
|
|
184
|
+
|
|
185
|
+
@abstractmethod
|
|
186
|
+
async def hot_count(self) -> int:
|
|
187
|
+
...
|
|
188
|
+
|
|
189
|
+
@abstractmethod
|
|
190
|
+
async def cold_count(self) -> int:
|
|
191
|
+
...
|
|
192
|
+
|
|
193
|
+
@abstractmethod
|
|
194
|
+
async def stub_count(self) -> int:
|
|
195
|
+
...
|
|
196
|
+
|
|
197
|
+
@abstractmethod
|
|
198
|
+
async def total_count(self) -> int:
|
|
199
|
+
...
|
|
200
|
+
|
|
201
|
+
# ------------------------------------------------------------------
|
|
202
|
+
# Batch operations
|
|
203
|
+
# ------------------------------------------------------------------
|
|
204
|
+
|
|
205
|
+
@abstractmethod
|
|
206
|
+
async def batch_update(self, memories: list[Memory]) -> None:
|
|
207
|
+
"""Update multiple memories at once."""
|
|
208
|
+
...
|
|
209
|
+
|
|
210
|
+
@abstractmethod
|
|
211
|
+
async def update_retention_scores(self, updates: dict[str, float]) -> None:
|
|
212
|
+
"""Bulk update retention scores: {memory_id: new_retention}."""
|
|
213
|
+
...
|
|
214
|
+
|
|
215
|
+
# ------------------------------------------------------------------
|
|
216
|
+
# Transactions
|
|
217
|
+
# ------------------------------------------------------------------
|
|
218
|
+
|
|
219
|
+
@abstractmethod
|
|
220
|
+
async def transaction(self, callback: Callable[["MemoryAdapter"], T]) -> T:
|
|
221
|
+
"""Execute callback within a transaction (adapter-specific)."""
|
|
222
|
+
...
|
|
223
|
+
|
|
224
|
+
# ------------------------------------------------------------------
|
|
225
|
+
# Reset
|
|
226
|
+
# ------------------------------------------------------------------
|
|
227
|
+
|
|
228
|
+
@abstractmethod
|
|
229
|
+
async def clear(self) -> None:
|
|
230
|
+
"""Clear all data."""
|
|
231
|
+
...
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
# Avoid circular import — just for type hints
|
|
235
|
+
from datetime import datetime # noqa: E402
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Convex adapter stub for cognitive-memory.
|
|
3
|
+
|
|
4
|
+
The Convex adapter is TypeScript-primary. See the TypeScript SDK for the
|
|
5
|
+
full implementation. This stub exists for cross-language parity.
|
|
6
|
+
|
|
7
|
+
Status: Not yet implemented. See https://github.com/bhekanik/cognitive-memory/issues
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
raise NotImplementedError(
|
|
11
|
+
"ConvexAdapter is TypeScript-primary. "
|
|
12
|
+
"See the TypeScript SDK for the full implementation."
|
|
13
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
JSONL file adapter stub for cognitive-memory.
|
|
3
|
+
|
|
4
|
+
The JSONL adapter is TypeScript-primary. See the TypeScript SDK for the
|
|
5
|
+
full implementation. This stub exists for cross-language parity.
|
|
6
|
+
|
|
7
|
+
Status: Not yet implemented. See https://github.com/bhekanik/cognitive-memory/issues
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
raise NotImplementedError(
|
|
11
|
+
"JsonlFileAdapter is TypeScript-primary. "
|
|
12
|
+
"See the TypeScript SDK for the full implementation."
|
|
13
|
+
)
|