rememhq 0.1.5__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.
@@ -0,0 +1,147 @@
1
+ # ========================
2
+ # Rust
3
+ # ========================
4
+ /target/
5
+ **/*.rs.bk
6
+ # Note: Cargo.lock is tracked intentionally — this workspace produces binary crates
7
+
8
+ # ========================
9
+ # C++ (libremem — v0.2+)
10
+ # ========================
11
+ /build/
12
+ /libremem/build/
13
+ *.o
14
+ *.a
15
+ *.so
16
+ *.dylib
17
+ *.dll
18
+ *.lib
19
+ *.exe
20
+ cmake-build-*/
21
+ CMakeFiles/
22
+ CMakeCache.txt
23
+
24
+ # ========================
25
+ # Python SDK
26
+ # ========================
27
+ __pycache__/
28
+ *.py[cod]
29
+ *$py.class
30
+ *.egg-info/
31
+ *.egg
32
+ dist/
33
+ .eggs/
34
+ .venv/
35
+ venv/
36
+ ENV/
37
+ .pytest_cache/
38
+ .mypy_cache/
39
+ .ruff_cache/
40
+ htmlcov/
41
+ .coverage
42
+ .coverage.*
43
+ *.cover
44
+
45
+ # ========================
46
+ # TypeScript SDK
47
+ # ========================
48
+ node_modules/
49
+ dist/
50
+ *.tsbuildinfo
51
+ .turbo/
52
+ coverage/
53
+ *.js.map
54
+
55
+ # ========================
56
+ # Models (large binaries)
57
+ # ========================
58
+ models/*.gguf
59
+ models/*.onnx
60
+ models/*.bin
61
+ models/*.safetensors
62
+
63
+ # ========================
64
+ # remem runtime data
65
+ # ========================
66
+ .remem/
67
+ *.db
68
+ *.db-wal
69
+ *.db-shm
70
+ *.index.json
71
+
72
+ # ========================
73
+ # Docker
74
+ # ========================
75
+ .docker/
76
+
77
+ # ========================
78
+ # IDE / Editor
79
+ # ========================
80
+ .vscode/
81
+ !.vscode/settings.json
82
+ !.vscode/extensions.json
83
+ .idea/
84
+ *.swp
85
+ *.swo
86
+ *~
87
+ *.sublime-workspace
88
+ *.sublime-project
89
+
90
+ # ========================
91
+ # OS generated
92
+ # ========================
93
+ .DS_Store
94
+ .DS_Store?
95
+ ._*
96
+ .Spotlight-V100
97
+ .Trashes
98
+ ehthumbs.db
99
+ Thumbs.db
100
+ desktop.ini
101
+
102
+ # ========================
103
+ # Environment / Secrets
104
+ # ========================
105
+ .env
106
+ .env.*
107
+ !.env.example
108
+
109
+ # ========================
110
+ # Agent / AI tool configs
111
+ # ========================
112
+ .claude/**/*
113
+ !.claude/config.json
114
+ .codex/
115
+ .gemini/
116
+ .cursor/**/*
117
+ !.cursor/hooks.json
118
+
119
+ # ========================
120
+ # Misc
121
+ # ========================
122
+ *.log
123
+ *.tmp
124
+ *.bak
125
+ *.orig
126
+
127
+ # ========================
128
+ # Swift Package Manager
129
+ # ========================
130
+ bindings/swift/.build/
131
+ bindings/swift/.swiftpm/
132
+ bindings/swift/Package.resolved
133
+
134
+ # ========================
135
+ # React Native / Expo module (bindings/react-native)
136
+ # ========================
137
+ bindings/react-native/build/
138
+ bindings/react-native/ios/Pods/
139
+ bindings/react-native/ios/build/
140
+ bindings/react-native/android/build/
141
+ bindings/react-native/android/.gradle/
142
+ bindings/react-native/android/.cxx/
143
+ bindings/react-native/android/rust/target/
144
+ bindings/react-native/example/node_modules/
145
+ bindings/react-native/example/ios/
146
+ bindings/react-native/example/android/
147
+ bindings/react-native/example/.expo/
rememhq-0.1.5/PKG-INFO ADDED
@@ -0,0 +1,208 @@
1
+ Metadata-Version: 2.4
2
+ Name: rememhq
3
+ Version: 0.1.5
4
+ Summary: Reasoning memory layer for AI agents — Python SDK
5
+ Project-URL: Homepage, https://github.com/remem-io/remem
6
+ Project-URL: Repository, https://github.com/remem-io/remem
7
+ Project-URL: Issues, https://github.com/remem-io/remem/issues
8
+ Project-URL: Changelog, https://github.com/remem-io/remem/blob/main/CHANGELOG.md
9
+ Project-URL: Documentation, https://github.com/remem-io/remem/tree/main/sdk/python
10
+ Author-email: remem-io <thrive-spectrexq@users.noreply.github.com>
11
+ License-Expression: Apache-2.0
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Database
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: httpx>=0.27
24
+ Requires-Dist: pydantic>=2.0
25
+ Provides-Extra: autogen
26
+ Requires-Dist: autogen-agentchat>=0.4; extra == 'autogen'
27
+ Provides-Extra: crewai
28
+ Requires-Dist: crewai>=0.80; extra == 'crewai'
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
31
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
32
+ Requires-Dist: pytest>=8.0; extra == 'dev'
33
+ Requires-Dist: respx>=0.21; extra == 'dev'
34
+ Provides-Extra: langchain
35
+ Requires-Dist: langchain-core>=0.3; extra == 'langchain'
36
+ Provides-Extra: llamaindex
37
+ Requires-Dist: llama-index-core>=0.11; extra == 'llamaindex'
38
+ Description-Content-Type: text/markdown
39
+
40
+ # remem Python SDK
41
+
42
+ This is the Python SDK for remem, providing a typed interface over the REST API.
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ pip install rememhq
48
+ ```
49
+
50
+ ## Quick Start
51
+
52
+ ```python
53
+ from rememhq import Memory
54
+
55
+ memory = Memory(base_url="http://localhost:7474")
56
+
57
+ # Store a memory
58
+ await memory.store("User prefers Python", tags=["language"])
59
+
60
+ # Recall memories
61
+ results = await memory.recall("what language does the user prefer?")
62
+ for result in results:
63
+ print(f"Content: {result.content}")
64
+ print(f"Reasoning: {result.reasoning}")
65
+ ```
66
+
67
+ ## Development
68
+
69
+ ### Prerequisites
70
+
71
+ - **Python** 3.11+
72
+ - **pip** or **uv**
73
+
74
+ ### Setup
75
+
76
+ ```bash
77
+ cd sdk/python
78
+
79
+ # Install in development mode with dev dependencies
80
+ pip install -e ".[dev]"
81
+ ```
82
+
83
+ ### Testing
84
+
85
+ ```bash
86
+ # Run all tests
87
+ pytest tests/ -v
88
+
89
+ # Run with coverage
90
+ pytest tests/ --cov=rememhq
91
+
92
+ # Run specific test
93
+ pytest tests/test_memory.py -v
94
+ ```
95
+
96
+ ### Code Quality
97
+
98
+ ```bash
99
+ # Format code
100
+ black rememhq/ tests/
101
+
102
+ # Lint
103
+ ruff check rememhq/ tests/
104
+
105
+ # Type checking
106
+ mypy rememhq/
107
+ ```
108
+
109
+ ### Building
110
+
111
+ ```bash
112
+ # Build distribution
113
+ python -m build
114
+
115
+ # Install locally from build
116
+ pip install dist/rememhq-*.whl
117
+ ```
118
+
119
+ ## Running the API Server
120
+
121
+ Before using the SDK, start the remem API server from the repository root:
122
+
123
+ ```bash
124
+ cargo run -p rememhq-api -- --project default
125
+ ```
126
+
127
+ The API will be available at `http://localhost:7474` by default.
128
+
129
+ ## API Reference
130
+
131
+ ### Memory
132
+
133
+ #### `store(content: str, tags: Optional[List[str]] = None, importance: Optional[float] = None) -> StoreResponse`
134
+
135
+ Store a memory with optional tags and importance score.
136
+
137
+ ```python
138
+ response = await memory.store(
139
+ "Production database is PostgreSQL 15",
140
+ tags=["infra", "database"],
141
+ importance=0.95
142
+ )
143
+ ```
144
+
145
+ #### `recall(query: str, limit: int = 8) -> List[RecallResult]`
146
+
147
+ Retrieve memories most relevant to the query, with reasoning traces.
148
+
149
+ ```python
150
+ results = await memory.recall("what database are we using?", limit=8)
151
+ for result in results:
152
+ print(f"Content: {result.content}")
153
+ print(f"Score: {result.score}")
154
+ print(f"Reasoning: {result.reasoning}")
155
+ ```
156
+
157
+ #### `search(query: str, limit: int = 10) -> List[SearchResult]`
158
+
159
+ Full-text search over all memories.
160
+
161
+ ```python
162
+ results = await memory.search("deployment", limit=10)
163
+ ```
164
+
165
+ #### `update(memory_id: str, content: str) -> UpdateResponse`
166
+
167
+ Update an existing memory's content.
168
+
169
+ #### `forget(memory_id: str) -> ForgetResponse`
170
+
171
+ Delete a memory.
172
+
173
+ #### `consolidate(session_id: str) -> ConsolidateResponse`
174
+
175
+ Consolidate session logs into durable facts.
176
+
177
+ ## Configuration
178
+
179
+ Configure the SDK via constructor parameters or environment variables:
180
+
181
+ ```python
182
+ from rememhq import Memory
183
+
184
+ memory = Memory(
185
+ base_url="http://localhost:7474",
186
+ project="my-agent",
187
+ reasoning_model="claude-sonnet-4-6",
188
+ timeout=30.0
189
+ )
190
+ ```
191
+
192
+ **Environment variables:**
193
+ - `REMEM_API_URL` — API server URL (default: `http://localhost:7474`)
194
+ - `REMEM_PROJECT` — Project name (default: `default`)
195
+ - `REMEM_REASONING_MODEL` — Reasoning model (default: `claude-sonnet-4-6`)
196
+ - `REMEM_TIMEOUT` — Request timeout in seconds (default: `30`)
197
+
198
+ ## Examples
199
+
200
+ Check the `examples/` directory for complete working scripts.
201
+
202
+ ## Contributing
203
+
204
+ See [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines on contributing to the Python SDK.
205
+
206
+ ## License
207
+
208
+ Apache License 2.0 — See [LICENSE](../../LICENSE) for details.
@@ -0,0 +1,169 @@
1
+ # remem Python SDK
2
+
3
+ This is the Python SDK for remem, providing a typed interface over the REST API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install rememhq
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ from rememhq import Memory
15
+
16
+ memory = Memory(base_url="http://localhost:7474")
17
+
18
+ # Store a memory
19
+ await memory.store("User prefers Python", tags=["language"])
20
+
21
+ # Recall memories
22
+ results = await memory.recall("what language does the user prefer?")
23
+ for result in results:
24
+ print(f"Content: {result.content}")
25
+ print(f"Reasoning: {result.reasoning}")
26
+ ```
27
+
28
+ ## Development
29
+
30
+ ### Prerequisites
31
+
32
+ - **Python** 3.11+
33
+ - **pip** or **uv**
34
+
35
+ ### Setup
36
+
37
+ ```bash
38
+ cd sdk/python
39
+
40
+ # Install in development mode with dev dependencies
41
+ pip install -e ".[dev]"
42
+ ```
43
+
44
+ ### Testing
45
+
46
+ ```bash
47
+ # Run all tests
48
+ pytest tests/ -v
49
+
50
+ # Run with coverage
51
+ pytest tests/ --cov=rememhq
52
+
53
+ # Run specific test
54
+ pytest tests/test_memory.py -v
55
+ ```
56
+
57
+ ### Code Quality
58
+
59
+ ```bash
60
+ # Format code
61
+ black rememhq/ tests/
62
+
63
+ # Lint
64
+ ruff check rememhq/ tests/
65
+
66
+ # Type checking
67
+ mypy rememhq/
68
+ ```
69
+
70
+ ### Building
71
+
72
+ ```bash
73
+ # Build distribution
74
+ python -m build
75
+
76
+ # Install locally from build
77
+ pip install dist/rememhq-*.whl
78
+ ```
79
+
80
+ ## Running the API Server
81
+
82
+ Before using the SDK, start the remem API server from the repository root:
83
+
84
+ ```bash
85
+ cargo run -p rememhq-api -- --project default
86
+ ```
87
+
88
+ The API will be available at `http://localhost:7474` by default.
89
+
90
+ ## API Reference
91
+
92
+ ### Memory
93
+
94
+ #### `store(content: str, tags: Optional[List[str]] = None, importance: Optional[float] = None) -> StoreResponse`
95
+
96
+ Store a memory with optional tags and importance score.
97
+
98
+ ```python
99
+ response = await memory.store(
100
+ "Production database is PostgreSQL 15",
101
+ tags=["infra", "database"],
102
+ importance=0.95
103
+ )
104
+ ```
105
+
106
+ #### `recall(query: str, limit: int = 8) -> List[RecallResult]`
107
+
108
+ Retrieve memories most relevant to the query, with reasoning traces.
109
+
110
+ ```python
111
+ results = await memory.recall("what database are we using?", limit=8)
112
+ for result in results:
113
+ print(f"Content: {result.content}")
114
+ print(f"Score: {result.score}")
115
+ print(f"Reasoning: {result.reasoning}")
116
+ ```
117
+
118
+ #### `search(query: str, limit: int = 10) -> List[SearchResult]`
119
+
120
+ Full-text search over all memories.
121
+
122
+ ```python
123
+ results = await memory.search("deployment", limit=10)
124
+ ```
125
+
126
+ #### `update(memory_id: str, content: str) -> UpdateResponse`
127
+
128
+ Update an existing memory's content.
129
+
130
+ #### `forget(memory_id: str) -> ForgetResponse`
131
+
132
+ Delete a memory.
133
+
134
+ #### `consolidate(session_id: str) -> ConsolidateResponse`
135
+
136
+ Consolidate session logs into durable facts.
137
+
138
+ ## Configuration
139
+
140
+ Configure the SDK via constructor parameters or environment variables:
141
+
142
+ ```python
143
+ from rememhq import Memory
144
+
145
+ memory = Memory(
146
+ base_url="http://localhost:7474",
147
+ project="my-agent",
148
+ reasoning_model="claude-sonnet-4-6",
149
+ timeout=30.0
150
+ )
151
+ ```
152
+
153
+ **Environment variables:**
154
+ - `REMEM_API_URL` — API server URL (default: `http://localhost:7474`)
155
+ - `REMEM_PROJECT` — Project name (default: `default`)
156
+ - `REMEM_REASONING_MODEL` — Reasoning model (default: `claude-sonnet-4-6`)
157
+ - `REMEM_TIMEOUT` — Request timeout in seconds (default: `30`)
158
+
159
+ ## Examples
160
+
161
+ Check the `examples/` directory for complete working scripts.
162
+
163
+ ## Contributing
164
+
165
+ See [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines on contributing to the Python SDK.
166
+
167
+ ## License
168
+
169
+ Apache License 2.0 — See [LICENSE](../../LICENSE) for details.
@@ -0,0 +1,55 @@
1
+ [project]
2
+ name = "rememhq"
3
+ version = "0.1.5"
4
+ description = "Reasoning memory layer for AI agents — Python SDK"
5
+ readme = "README.md"
6
+ license = "Apache-2.0"
7
+ requires-python = ">=3.11"
8
+ authors = [
9
+ { name = "remem-io", email = "thrive-spectrexq@users.noreply.github.com" },
10
+ ]
11
+ classifiers = [
12
+ "Development Status :: 3 - Alpha",
13
+ "Intended Audience :: Developers",
14
+ "License :: OSI Approved :: Apache Software License",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
20
+ "Topic :: Database",
21
+ "Typing :: Typed",
22
+ ]
23
+ dependencies = [
24
+ "httpx>=0.27",
25
+ "pydantic>=2.0",
26
+ ]
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/remem-io/remem"
30
+ Repository = "https://github.com/remem-io/remem"
31
+ Issues = "https://github.com/remem-io/remem/issues"
32
+ Changelog = "https://github.com/remem-io/remem/blob/main/CHANGELOG.md"
33
+ Documentation = "https://github.com/remem-io/remem/tree/main/sdk/python"
34
+
35
+ [project.optional-dependencies]
36
+ dev = [
37
+ "pytest>=8.0",
38
+ "pytest-asyncio>=0.23",
39
+ "pytest-cov>=5.0",
40
+ "respx>=0.21",
41
+ ]
42
+ langchain = ["langchain-core>=0.3"]
43
+ llamaindex = ["llama-index-core>=0.11"]
44
+ autogen = ["autogen-agentchat>=0.4"]
45
+ crewai = ["crewai>=0.80"]
46
+
47
+ [build-system]
48
+ requires = ["hatchling"]
49
+ build-backend = "hatchling.build"
50
+
51
+ [tool.hatch.build.targets.sdist]
52
+ include = ["rememhq/"]
53
+
54
+ [tool.hatch.build.targets.wheel]
55
+ packages = ["rememhq"]
@@ -0,0 +1,7 @@
1
+ """remem — reasoning memory layer for AI agents."""
2
+
3
+ from rememhq.client import Memory
4
+ from rememhq.models import MemoryResult, ConsolidationReport, StoreResponse
5
+
6
+ __all__ = ["Memory", "MemoryResult", "ConsolidationReport", "StoreResponse"]
7
+ __version__ = "0.1.5"
@@ -0,0 +1,269 @@
1
+ """Async-first Python client for the remem REST API."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import datetime
6
+ from uuid import UUID
7
+
8
+ import httpx
9
+
10
+ from rememhq.config import RememConfig
11
+ from rememhq.models import (
12
+ ConsolidationReport,
13
+ CompactResponse,
14
+ ForgetMode,
15
+ MemoryResult,
16
+ MemoryType,
17
+ StoreResponse,
18
+ MemoryStoreRecord,
19
+ MemoryVersionRecord,
20
+ )
21
+
22
+
23
+ class Memory:
24
+ """Async client for remem — reasoning memory layer for AI agents.
25
+
26
+ Example:
27
+ >>> m = Memory(project="my-agent", reasoning_model="claude-sonnet-4-5")
28
+ >>> await m.store("User prefers dark mode", tags=["preferences"])
29
+ >>> results = await m.recall("what are the user's preferences?")
30
+ """
31
+
32
+ def __init__(
33
+ self,
34
+ project: str = "default",
35
+ reasoning_model: str = "claude-sonnet-4-5",
36
+ scoring_model: str = "claude-haiku-4-5",
37
+ base_url: str | None = None,
38
+ api_key: str | None = None,
39
+ timeout: float = 30.0,
40
+ ):
41
+ config = RememConfig(
42
+ project=project,
43
+ reasoning_model=reasoning_model,
44
+ scoring_model=scoring_model,
45
+ timeout=timeout,
46
+ )
47
+ if base_url:
48
+ config.base_url = base_url
49
+ if api_key:
50
+ config.api_key = api_key
51
+
52
+ self._config = config
53
+ headers: dict[str, str] = {"Content-Type": "application/json"}
54
+ if config.api_key:
55
+ headers["Authorization"] = f"Bearer {config.api_key}"
56
+
57
+ self._client = httpx.AsyncClient(
58
+ base_url=config.base_url,
59
+ headers=headers,
60
+ timeout=config.timeout,
61
+ )
62
+ self.stores = MemoryStoresClient(self._client)
63
+
64
+ async def store(
65
+ self,
66
+ content: str,
67
+ *,
68
+ tags: list[str] | None = None,
69
+ importance: float | None = None,
70
+ ttl_days: int | None = None,
71
+ memory_type: MemoryType = MemoryType.FACT,
72
+ ) -> StoreResponse:
73
+ """Store a new memory with automatic LLM importance scoring."""
74
+ payload: dict = {
75
+ "content": content,
76
+ "tags": tags or [],
77
+ "memory_type": memory_type.value,
78
+ }
79
+ if importance is not None:
80
+ payload["importance"] = importance
81
+ if ttl_days is not None:
82
+ payload["ttl_days"] = ttl_days
83
+
84
+ resp = await self._client.post("/v1/memories", json=payload)
85
+ resp.raise_for_status()
86
+ return StoreResponse.model_validate(resp.json())
87
+
88
+ async def recall(
89
+ self,
90
+ query: str,
91
+ *,
92
+ limit: int = 8,
93
+ filter_tags: list[str] | None = None,
94
+ since: datetime | None = None,
95
+ memory_type: MemoryType | None = None,
96
+ ) -> list[MemoryResult]:
97
+ """Guided recall — LLM re-ranks candidates for relevance."""
98
+ params: dict = {"q": query, "limit": limit}
99
+ if filter_tags:
100
+ params["filter_tags"] = ",".join(filter_tags)
101
+ if since:
102
+ params["since"] = since.isoformat()
103
+ if memory_type:
104
+ params["memory_type"] = memory_type.value
105
+
106
+ resp = await self._client.get("/v1/memories/recall", params=params)
107
+ resp.raise_for_status()
108
+ return [MemoryResult.model_validate(r) for r in resp.json()]
109
+
110
+ async def search(
111
+ self,
112
+ query: str,
113
+ *,
114
+ limit: int = 20,
115
+ filter_tags: list[str] | None = None,
116
+ ) -> list[MemoryResult]:
117
+ """Hybrid vector + keyword search without LLM re-ranking."""
118
+ params: dict = {"q": query, "limit": limit}
119
+ if filter_tags:
120
+ params["filter_tags"] = ",".join(filter_tags)
121
+
122
+ resp = await self._client.get("/v1/memories/search", params=params)
123
+ resp.raise_for_status()
124
+ return [MemoryResult.model_validate(r) for r in resp.json()]
125
+
126
+ async def update(
127
+ self,
128
+ id: UUID | str,
129
+ *,
130
+ content: str | None = None,
131
+ importance: float | None = None,
132
+ tags: list[str] | None = None,
133
+ ) -> dict:
134
+ """Update an existing memory."""
135
+ payload: dict = {}
136
+ if content is not None:
137
+ payload["content"] = content
138
+ if importance is not None:
139
+ payload["importance"] = importance
140
+ if tags is not None:
141
+ payload["tags"] = tags
142
+
143
+ resp = await self._client.patch(f"/v1/memories/{id}", json=payload)
144
+ resp.raise_for_status()
145
+ return resp.json()
146
+
147
+ async def forget(
148
+ self,
149
+ id: UUID | str,
150
+ *,
151
+ mode: ForgetMode = ForgetMode.DELETE,
152
+ ) -> dict:
153
+ """Delete, decay, or archive a memory."""
154
+ resp = await self._client.delete(
155
+ f"/v1/memories/{id}", params={"mode": mode.value}
156
+ )
157
+ resp.raise_for_status()
158
+ return resp.json()
159
+
160
+ async def consolidate(
161
+ self,
162
+ session_id: str,
163
+ *,
164
+ model: str | None = None,
165
+ ) -> ConsolidationReport:
166
+ """Trigger consolidation over a session's working memory."""
167
+ payload: dict = {}
168
+ if model:
169
+ payload["model"] = model
170
+
171
+ resp = await self._client.post(
172
+ f"/v1/sessions/{session_id}/consolidate", json=payload
173
+ )
174
+ resp.raise_for_status()
175
+ return ConsolidationReport.model_validate(resp.json())
176
+
177
+ async def decay(self, factor: float = 0.9) -> dict:
178
+ """Apply importance-weighted decay to all active memories."""
179
+ resp = await self._client.post("/v1/memories/decay", json={"factor": factor})
180
+ resp.raise_for_status()
181
+ return resp.json()
182
+
183
+ async def compact_context(
184
+ self,
185
+ conversation_text: str,
186
+ *,
187
+ focus_areas: list[str] | None = None,
188
+ ) -> CompactResponse:
189
+ """Compact a conversation trace to save context window tokens."""
190
+ payload: dict = {"conversation_text": conversation_text}
191
+ if focus_areas is not None:
192
+ payload["focus_areas"] = focus_areas
193
+
194
+ resp = await self._client.post("/v1/memories/compact", json=payload)
195
+ resp.raise_for_status()
196
+ return CompactResponse.model_validate(resp.json())
197
+
198
+ async def close(self) -> None:
199
+ """Close the HTTP client."""
200
+ await self._client.aclose()
201
+
202
+ async def __aenter__(self) -> "Memory":
203
+ return self
204
+
205
+ async def __aexit__(self, *args) -> None:
206
+ await self.close()
207
+
208
+ class StoreMemoriesClient:
209
+ def __init__(self, client: httpx.AsyncClient):
210
+ self._client = client
211
+
212
+ async def list(self, store_id: str | UUID) -> list[MemoryResult]:
213
+ resp = await self._client.get(f"/v1/memory_stores/{store_id}/memories")
214
+ resp.raise_for_status()
215
+ return [MemoryResult.model_validate(r) for r in resp.json()]
216
+
217
+ async def create(self, store_id: str | UUID, path: str, content: str) -> MemoryResult:
218
+ resp = await self._client.post(
219
+ f"/v1/memory_stores/{store_id}/memories",
220
+ json={"path": path, "content": content}
221
+ )
222
+ resp.raise_for_status()
223
+ return MemoryResult.model_validate(resp.json())
224
+
225
+ async def get(self, store_id: str | UUID, path_or_id: str | UUID) -> MemoryResult:
226
+ resp = await self._client.get(f"/v1/memory_stores/{store_id}/memories/{path_or_id}")
227
+ resp.raise_for_status()
228
+ return MemoryResult.model_validate(resp.json())
229
+
230
+ async def update(self, store_id: str | UUID, path_or_id: str | UUID, content: str) -> MemoryResult:
231
+ resp = await self._client.post(
232
+ f"/v1/memory_stores/{store_id}/memories/{path_or_id}",
233
+ json={"content": content}
234
+ )
235
+ resp.raise_for_status()
236
+ return MemoryResult.model_validate(resp.json())
237
+
238
+ async def list_versions(self, store_id: str | UUID, path_or_id: str | UUID) -> list[MemoryVersionRecord]:
239
+ resp = await self._client.get(f"/v1/memory_stores/{store_id}/memories/{path_or_id}/versions")
240
+ resp.raise_for_status()
241
+ return [MemoryVersionRecord.model_validate(r) for r in resp.json()]
242
+
243
+
244
+ class MemoryStoresClient:
245
+ def __init__(self, client: httpx.AsyncClient):
246
+ self._client = client
247
+ self.memories = StoreMemoriesClient(client)
248
+
249
+ async def create(self, name: str, description: str | None = None) -> MemoryStoreRecord:
250
+ payload = {"name": name}
251
+ if description:
252
+ payload["description"] = description
253
+ resp = await self._client.post("/v1/memory_stores", json=payload)
254
+ resp.raise_for_status()
255
+ return MemoryStoreRecord.model_validate(resp.json())
256
+
257
+ async def list(self) -> list[MemoryStoreRecord]:
258
+ resp = await self._client.get("/v1/memory_stores")
259
+ resp.raise_for_status()
260
+ return [MemoryStoreRecord.model_validate(r) for r in resp.json()]
261
+
262
+ async def get(self, store_id: str | UUID) -> MemoryStoreRecord:
263
+ resp = await self._client.get(f"/v1/memory_stores/{store_id}")
264
+ resp.raise_for_status()
265
+ return MemoryStoreRecord.model_validate(resp.json())
266
+
267
+ async def archive(self, store_id: str | UUID) -> None:
268
+ resp = await self._client.post(f"/v1/memory_stores/{store_id}/archive")
269
+ resp.raise_for_status()
@@ -0,0 +1,32 @@
1
+ """Configuration for the remem Python SDK."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from dataclasses import dataclass, field
7
+
8
+
9
+ @dataclass
10
+ class RememConfig:
11
+ """Configuration for connecting to a remem server."""
12
+
13
+ base_url: str = field(
14
+ default_factory=lambda: os.environ.get(
15
+ "REMEM_BASE_URL", "http://localhost:7474"
16
+ )
17
+ )
18
+ api_key: str | None = field(default_factory=lambda: os.environ.get("REMEM_API_KEY"))
19
+ project: str = field(
20
+ default_factory=lambda: os.environ.get("REMEM_PROJECT", "default")
21
+ )
22
+ reasoning_model: str = field(
23
+ default_factory=lambda: os.environ.get(
24
+ "REMEM_REASONING_MODEL", "claude-sonnet-4-5"
25
+ )
26
+ )
27
+ scoring_model: str = field(
28
+ default_factory=lambda: os.environ.get(
29
+ "REMEM_SCORING_MODEL", "claude-haiku-4-5"
30
+ )
31
+ )
32
+ timeout: float = 30.0
@@ -0,0 +1,90 @@
1
+ """Pydantic v2 models for the remem REST API."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import datetime
6
+ from enum import Enum
7
+ from typing import Optional
8
+ from uuid import UUID
9
+
10
+ from pydantic import BaseModel, Field
11
+
12
+
13
+ class MemoryType(str, Enum):
14
+ FACT = "fact"
15
+ PROCEDURE = "procedure"
16
+ PREFERENCE = "preference"
17
+ DECISION = "decision"
18
+
19
+
20
+ class ForgetMode(str, Enum):
21
+ DELETE = "delete"
22
+ DECAY = "decay"
23
+ ARCHIVE = "archive"
24
+
25
+
26
+ class StoreResponse(BaseModel):
27
+ id: UUID
28
+ importance: float
29
+ tags: list[str]
30
+ created_at: datetime
31
+
32
+
33
+ class CompactResponse(BaseModel):
34
+ compressed_context: str
35
+ original_length: int
36
+ compressed_length: int
37
+
38
+
39
+ class MemoryResult(BaseModel):
40
+ id: UUID
41
+ content: str
42
+ importance: float
43
+ tags: list[str]
44
+ memory_type: MemoryType
45
+ created_at: datetime
46
+ source_session: Optional[str] = None
47
+ similarity: float = 0.0
48
+ decay_score: float = 1.0
49
+ reasoning: Optional[str] = None
50
+
51
+
52
+ class ConsolidationReport(BaseModel):
53
+ session_id: str
54
+ new_facts: int
55
+ updated_facts: int
56
+ contradictions: list[Contradiction] = Field(default_factory=list)
57
+ knowledge_graph_updates: list[KnowledgeGraphUpdate] = Field(default_factory=list)
58
+
59
+
60
+ class Contradiction(BaseModel):
61
+ existing_memory_id: UUID
62
+ new_content: str
63
+ existing_content: str
64
+ explanation: str
65
+
66
+
67
+ class KnowledgeGraphUpdate(BaseModel):
68
+ subject: str
69
+ predicate: str
70
+ object: str
71
+
72
+
73
+ # Fix forward references
74
+ ConsolidationReport.model_rebuild()
75
+
76
+ class MemoryStoreRecord(BaseModel):
77
+ id: str
78
+ name: str
79
+ description: Optional[str] = None
80
+ created_at: datetime
81
+ archived_at: Optional[datetime] = None
82
+
83
+ class MemoryVersionRecord(BaseModel):
84
+ id: str
85
+ store_id: str
86
+ memory_id: UUID
87
+ operation: str
88
+ content: str
89
+ content_sha256: str
90
+ created_at: datetime