atomicmemory 1.0.0__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.
- atomicmemory/__init__.py +166 -0
- atomicmemory/_version.py +3 -0
- atomicmemory/client/__init__.py +22 -0
- atomicmemory/client/async_memory_client.py +202 -0
- atomicmemory/client/atomic_memory_client.py +181 -0
- atomicmemory/client/memory_client.py +292 -0
- atomicmemory/core/__init__.py +34 -0
- atomicmemory/core/errors.py +122 -0
- atomicmemory/core/events.py +65 -0
- atomicmemory/core/logging.py +37 -0
- atomicmemory/core/retry.py +124 -0
- atomicmemory/core/validation.py +22 -0
- atomicmemory/embeddings/__init__.py +16 -0
- atomicmemory/embeddings/base.py +39 -0
- atomicmemory/embeddings/sentence_transformers.py +104 -0
- atomicmemory/kv_cache/__init__.py +17 -0
- atomicmemory/kv_cache/adapter.py +50 -0
- atomicmemory/kv_cache/memory_storage.py +98 -0
- atomicmemory/kv_cache/sqlite_storage.py +122 -0
- atomicmemory/memory/__init__.py +82 -0
- atomicmemory/memory/filters.py +68 -0
- atomicmemory/memory/pipeline.py +42 -0
- atomicmemory/memory/provider.py +397 -0
- atomicmemory/memory/registry.py +95 -0
- atomicmemory/memory/service.py +199 -0
- atomicmemory/memory/types.py +398 -0
- atomicmemory/providers/__init__.py +5 -0
- atomicmemory/providers/atomicmemory/__init__.py +43 -0
- atomicmemory/providers/atomicmemory/agents.py +156 -0
- atomicmemory/providers/atomicmemory/async_handle_impl.py +198 -0
- atomicmemory/providers/atomicmemory/async_provider.py +245 -0
- atomicmemory/providers/atomicmemory/audit.py +74 -0
- atomicmemory/providers/atomicmemory/config.py +38 -0
- atomicmemory/providers/atomicmemory/config_handle.py +123 -0
- atomicmemory/providers/atomicmemory/handle.py +513 -0
- atomicmemory/providers/atomicmemory/handle_impl.py +325 -0
- atomicmemory/providers/atomicmemory/http.py +255 -0
- atomicmemory/providers/atomicmemory/lessons.py +133 -0
- atomicmemory/providers/atomicmemory/lifecycle.py +202 -0
- atomicmemory/providers/atomicmemory/mappers.py +125 -0
- atomicmemory/providers/atomicmemory/path.py +20 -0
- atomicmemory/providers/atomicmemory/provider.py +300 -0
- atomicmemory/providers/atomicmemory/scope_mapper.py +98 -0
- atomicmemory/providers/mem0/__init__.py +41 -0
- atomicmemory/providers/mem0/async_provider.py +191 -0
- atomicmemory/providers/mem0/config.py +51 -0
- atomicmemory/providers/mem0/http.py +195 -0
- atomicmemory/providers/mem0/mappers.py +145 -0
- atomicmemory/providers/mem0/provider.py +202 -0
- atomicmemory/py.typed +0 -0
- atomicmemory/search/__init__.py +47 -0
- atomicmemory/search/chunking.py +161 -0
- atomicmemory/search/ranking.py +94 -0
- atomicmemory/search/semantic_search.py +130 -0
- atomicmemory/search/similarity.py +110 -0
- atomicmemory/storage/__init__.py +63 -0
- atomicmemory/storage/_mapping.py +305 -0
- atomicmemory/storage/async_client.py +208 -0
- atomicmemory/storage/client.py +339 -0
- atomicmemory/storage/errors.py +115 -0
- atomicmemory/storage/types.py +305 -0
- atomicmemory/utils/__init__.py +5 -0
- atomicmemory/utils/environment.py +23 -0
- atomicmemory-1.0.0.dist-info/METADATA +146 -0
- atomicmemory-1.0.0.dist-info/RECORD +67 -0
- atomicmemory-1.0.0.dist-info/WHEEL +4 -0
- atomicmemory-1.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"""Types for the backend artifact-storage API.
|
|
2
|
+
|
|
3
|
+
Port of `atomicmemory-sdk/src/storage/types.ts`. Python callers use
|
|
4
|
+
snake_case field names while Pydantic aliases accept the TypeScript
|
|
5
|
+
SDK's camelCase spellings at the public boundary.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any, Literal
|
|
11
|
+
from urllib.parse import urlparse
|
|
12
|
+
|
|
13
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
|
14
|
+
|
|
15
|
+
StorageArtifactStatus = Literal[
|
|
16
|
+
"stored",
|
|
17
|
+
"pending",
|
|
18
|
+
"available",
|
|
19
|
+
"unavailable",
|
|
20
|
+
"deleting",
|
|
21
|
+
"deleted",
|
|
22
|
+
"delete_failed",
|
|
23
|
+
"failed",
|
|
24
|
+
]
|
|
25
|
+
StorageAddressingMode = Literal["location", "content", "provider_native"]
|
|
26
|
+
StorageConsistency = Literal["immediate", "eventual"]
|
|
27
|
+
StorageAvailabilityModel = Literal["immediate", "delayed", "scheduled", "best_effort"]
|
|
28
|
+
StorageDeleteSemantics = Literal["delete", "unpin", "tombstone", "provider_retained"]
|
|
29
|
+
StorageMode = Literal["pointer", "managed"]
|
|
30
|
+
ContentEncoding = Literal["identity", "aes_gcm"]
|
|
31
|
+
DeleteArtifactPolicy = Literal["artifact_only", "with_documents"]
|
|
32
|
+
ArtifactMetadata = dict[str, str | int | float | bool]
|
|
33
|
+
ManagedBody = bytes | bytearray | memoryview
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class StorageClientConfig(BaseModel):
|
|
37
|
+
"""Configuration for sync and async storage clients."""
|
|
38
|
+
|
|
39
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
40
|
+
|
|
41
|
+
api_url: str = Field(alias="apiUrl")
|
|
42
|
+
api_key: str = Field(alias="apiKey")
|
|
43
|
+
user_id: str = Field(alias="userId")
|
|
44
|
+
timeout_seconds: float = Field(default=30.0, alias="timeoutSeconds")
|
|
45
|
+
|
|
46
|
+
@field_validator("api_url")
|
|
47
|
+
@classmethod
|
|
48
|
+
def _validate_api_url(cls, value: str) -> str:
|
|
49
|
+
stripped = value.strip()
|
|
50
|
+
parsed = urlparse(stripped)
|
|
51
|
+
if parsed.scheme not in {"http", "https"} or not parsed.netloc:
|
|
52
|
+
raise ValueError("api_url must be an http(s) URL")
|
|
53
|
+
return stripped
|
|
54
|
+
|
|
55
|
+
@field_validator("api_key", "user_id")
|
|
56
|
+
@classmethod
|
|
57
|
+
def _validate_non_empty_secret(cls, value: str) -> str:
|
|
58
|
+
stripped = value.strip()
|
|
59
|
+
if stripped == "":
|
|
60
|
+
raise ValueError("value must not be empty")
|
|
61
|
+
return stripped
|
|
62
|
+
|
|
63
|
+
@field_validator("timeout_seconds")
|
|
64
|
+
@classmethod
|
|
65
|
+
def _validate_timeout(cls, value: float) -> float:
|
|
66
|
+
if value <= 0:
|
|
67
|
+
raise ValueError("timeout_seconds must be greater than zero")
|
|
68
|
+
return value
|
|
69
|
+
|
|
70
|
+
@model_validator(mode="after")
|
|
71
|
+
def _require_non_empty(self) -> StorageClientConfig:
|
|
72
|
+
if not self.api_url:
|
|
73
|
+
raise ValueError("api_url is required")
|
|
74
|
+
if not self.api_key:
|
|
75
|
+
raise ValueError("api_key is required")
|
|
76
|
+
if not self.user_id:
|
|
77
|
+
raise ValueError("user_id is required")
|
|
78
|
+
return self
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class ArtifactRef(BaseModel):
|
|
82
|
+
"""Stable reference to a storage artifact.
|
|
83
|
+
|
|
84
|
+
At least one identifier is required. v1 follow-up operations use
|
|
85
|
+
``artifact_id`` as the canonical handle.
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
89
|
+
|
|
90
|
+
artifact_id: str | None = Field(default=None, alias="artifactId")
|
|
91
|
+
uri: str | None = None
|
|
92
|
+
content_hash: str | None = Field(default=None, alias="contentHash")
|
|
93
|
+
|
|
94
|
+
@model_validator(mode="after")
|
|
95
|
+
def _require_one_identifier(self) -> ArtifactRef:
|
|
96
|
+
if self.artifact_id is None and self.uri is None and self.content_hash is None:
|
|
97
|
+
raise ValueError("ArtifactRef requires artifact_id, uri, or content_hash")
|
|
98
|
+
return self
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class StorageLifecycle(BaseModel):
|
|
102
|
+
"""Provider-agnostic availability and delete-semantics summary."""
|
|
103
|
+
|
|
104
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
105
|
+
|
|
106
|
+
availability: StorageAvailabilityModel | None = None
|
|
107
|
+
delete_semantics: StorageDeleteSemantics | None = Field(default=None, alias="deleteSemantics")
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class ReplicationState(BaseModel):
|
|
111
|
+
"""Optional replication state for backends such as Filecoin."""
|
|
112
|
+
|
|
113
|
+
model_config = ConfigDict(extra="ignore", populate_by_name=True)
|
|
114
|
+
|
|
115
|
+
desired_copies: int | None = Field(default=None, alias="desiredCopies")
|
|
116
|
+
confirmed_copies: int | None = Field(default=None, alias="confirmedCopies")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class VerificationState(BaseModel):
|
|
120
|
+
"""Optional provider-proof or content-verification state."""
|
|
121
|
+
|
|
122
|
+
model_config = ConfigDict(extra="ignore", populate_by_name=True)
|
|
123
|
+
|
|
124
|
+
provider_proof_status: Literal["pending", "verified", "failed", "unsupported"] | None = Field(
|
|
125
|
+
default=None,
|
|
126
|
+
alias="providerProofStatus",
|
|
127
|
+
)
|
|
128
|
+
last_verified_at: str | None = Field(default=None, alias="lastVerifiedAt")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class RetrievalState(BaseModel):
|
|
132
|
+
"""Optional retrieval-readiness state."""
|
|
133
|
+
|
|
134
|
+
model_config = ConfigDict(extra="ignore", populate_by_name=True)
|
|
135
|
+
|
|
136
|
+
status: Literal["not_checked", "retrievable", "not_retrievable", "unsupported"] | None = None
|
|
137
|
+
last_checked_at: str | None = Field(default=None, alias="lastCheckedAt")
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class StoredArtifact(BaseModel):
|
|
141
|
+
"""Artifact metadata returned by ``storage.put`` and ``storage.get``."""
|
|
142
|
+
|
|
143
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
144
|
+
|
|
145
|
+
artifact_id: str = Field(alias="artifactId")
|
|
146
|
+
provider: str
|
|
147
|
+
mode: StorageMode
|
|
148
|
+
uri: str | None
|
|
149
|
+
status: StorageArtifactStatus
|
|
150
|
+
size_bytes: int | None = Field(alias="sizeBytes")
|
|
151
|
+
content_type: str | None = Field(alias="contentType")
|
|
152
|
+
content_hash: str | None = Field(default=None, alias="contentHash")
|
|
153
|
+
content_encoding: ContentEncoding = Field(alias="contentEncoding")
|
|
154
|
+
identifiers: dict[str, str] = Field(default_factory=dict)
|
|
155
|
+
lifecycle: StorageLifecycle = Field(default_factory=StorageLifecycle)
|
|
156
|
+
replication: ReplicationState | None = None
|
|
157
|
+
verification: VerificationState | None = None
|
|
158
|
+
retrieval: RetrievalState | None = None
|
|
159
|
+
provider_details: dict[str, Any] | None = Field(default=None, alias="providerDetails")
|
|
160
|
+
metadata: ArtifactMetadata = Field(default_factory=dict)
|
|
161
|
+
created_at: str = Field(alias="createdAt")
|
|
162
|
+
updated_at: str = Field(alias="updatedAt")
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class ArtifactRange(BaseModel):
|
|
166
|
+
"""Byte range for future range-read capable storage backends."""
|
|
167
|
+
|
|
168
|
+
model_config = ConfigDict(extra="forbid")
|
|
169
|
+
|
|
170
|
+
start: int
|
|
171
|
+
end: int
|
|
172
|
+
|
|
173
|
+
@model_validator(mode="after")
|
|
174
|
+
def _validate_range(self) -> ArtifactRange:
|
|
175
|
+
if self.start < 0:
|
|
176
|
+
raise ValueError("start must be non-negative")
|
|
177
|
+
if self.end < self.start:
|
|
178
|
+
raise ValueError("end must be greater than or equal to start")
|
|
179
|
+
return self
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class PutPointerInput(BaseModel):
|
|
183
|
+
"""Pointer-mode put input. The server stores metadata only."""
|
|
184
|
+
|
|
185
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
186
|
+
|
|
187
|
+
mode: Literal["pointer"] = "pointer"
|
|
188
|
+
uri: str
|
|
189
|
+
content_type: str = Field(alias="contentType")
|
|
190
|
+
size_bytes: int | None = Field(default=None, alias="sizeBytes")
|
|
191
|
+
content_hash: str | None = Field(default=None, alias="contentHash")
|
|
192
|
+
metadata: ArtifactMetadata | None = None
|
|
193
|
+
|
|
194
|
+
@field_validator("content_type")
|
|
195
|
+
@classmethod
|
|
196
|
+
def _validate_content_type(cls, value: str) -> str:
|
|
197
|
+
stripped = value.strip()
|
|
198
|
+
if stripped == "":
|
|
199
|
+
raise ValueError("content_type must not be empty")
|
|
200
|
+
return stripped
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class PutManagedInput(BaseModel):
|
|
204
|
+
"""Managed-mode put input for known-length byte bodies."""
|
|
205
|
+
|
|
206
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True, arbitrary_types_allowed=True)
|
|
207
|
+
|
|
208
|
+
mode: Literal["managed"] = "managed"
|
|
209
|
+
body: ManagedBody
|
|
210
|
+
content_type: str = Field(alias="contentType")
|
|
211
|
+
disclose_content_hash: bool = Field(default=False, alias="discloseContentHash")
|
|
212
|
+
metadata: ArtifactMetadata | None = None
|
|
213
|
+
|
|
214
|
+
@field_validator("body", mode="before")
|
|
215
|
+
@classmethod
|
|
216
|
+
def _validate_body(cls, value: Any) -> Any:
|
|
217
|
+
if isinstance(value, bytes | bytearray | memoryview):
|
|
218
|
+
return value
|
|
219
|
+
raise ValueError("body must be bytes, bytearray, or memoryview")
|
|
220
|
+
|
|
221
|
+
@field_validator("content_type")
|
|
222
|
+
@classmethod
|
|
223
|
+
def _validate_content_type(cls, value: str) -> str:
|
|
224
|
+
stripped = value.strip()
|
|
225
|
+
if stripped == "":
|
|
226
|
+
raise ValueError("content_type must not be empty")
|
|
227
|
+
return stripped
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
PutArtifactInput = PutPointerInput | PutManagedInput
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class ArtifactHead(BaseModel):
|
|
234
|
+
"""Metadata projection returned by ``storage.head``."""
|
|
235
|
+
|
|
236
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
237
|
+
|
|
238
|
+
artifact_id: str = Field(alias="artifactId")
|
|
239
|
+
provider: str
|
|
240
|
+
mode: StorageMode
|
|
241
|
+
status: StorageArtifactStatus
|
|
242
|
+
size_bytes: int | None = Field(alias="sizeBytes")
|
|
243
|
+
content_type: str | None = Field(alias="contentType")
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
class DeleteArtifactOptions(BaseModel):
|
|
247
|
+
"""Options for ``storage.delete``."""
|
|
248
|
+
|
|
249
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
250
|
+
|
|
251
|
+
policy: DeleteArtifactPolicy | None = None
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class DeleteArtifactResult(BaseModel):
|
|
255
|
+
"""Result returned by ``storage.delete``."""
|
|
256
|
+
|
|
257
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
258
|
+
|
|
259
|
+
artifact_id: str = Field(alias="artifactId")
|
|
260
|
+
status: StorageArtifactStatus
|
|
261
|
+
cascaded_document_ids: list[str] | None = Field(default=None, alias="cascadedDocumentIds")
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class VerifyArtifactOptions(BaseModel):
|
|
265
|
+
"""Reserved verification options for future storage backends."""
|
|
266
|
+
|
|
267
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
268
|
+
|
|
269
|
+
mode: Literal["head_only", "hash_verify"] | None = None
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class VerificationResult(BaseModel):
|
|
273
|
+
"""Provider verification result."""
|
|
274
|
+
|
|
275
|
+
model_config = ConfigDict(extra="forbid")
|
|
276
|
+
|
|
277
|
+
kind: Literal["verified", "failed", "unsupported"]
|
|
278
|
+
details: dict[str, Any] | None = None
|
|
279
|
+
reason: str | None = None
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
class StorageCapabilities(BaseModel):
|
|
283
|
+
"""Direct storage API capability snapshot."""
|
|
284
|
+
|
|
285
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
286
|
+
|
|
287
|
+
provider: str
|
|
288
|
+
addressing: list[StorageAddressingMode]
|
|
289
|
+
consistency: StorageConsistency
|
|
290
|
+
max_upload_bytes: int | None = Field(default=None, alias="maxUploadBytes")
|
|
291
|
+
min_upload_bytes: int | None = Field(default=None, alias="minUploadBytes")
|
|
292
|
+
supports_direct_upload: bool = Field(alias="supportsDirectUpload")
|
|
293
|
+
supports_range_read: bool = Field(alias="supportsRangeRead")
|
|
294
|
+
supports_delete: bool = Field(alias="supportsDelete")
|
|
295
|
+
supports_tombstone: bool = Field(alias="supportsTombstone")
|
|
296
|
+
supports_bundles: bool = Field(alias="supportsBundles")
|
|
297
|
+
supported_bundle_formats: list[str] = Field(alias="supportedBundleFormats")
|
|
298
|
+
supports_verification: bool = Field(alias="supportsVerification")
|
|
299
|
+
supports_provider_proofs: bool = Field(alias="supportsProviderProofs")
|
|
300
|
+
supports_replication: bool = Field(alias="supportsReplication")
|
|
301
|
+
supports_retrieval_status: bool = Field(alias="supportsRetrievalStatus")
|
|
302
|
+
supports_content_hash: bool = Field(alias="supportsContentHash")
|
|
303
|
+
supports_content_addressed_uri: bool = Field(alias="supportsContentAddressedUri")
|
|
304
|
+
delete_semantics: list[StorageDeleteSemantics] = Field(alias="deleteSemantics")
|
|
305
|
+
availability_model: StorageAvailabilityModel = Field(alias="availabilityModel")
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Environment introspection helpers.
|
|
2
|
+
|
|
3
|
+
Port of `atomicmemory-sdk/src/utils/environment.ts`. Used internally to
|
|
4
|
+
gate noisy diagnostics and skip optional behavior in tests.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def is_test_environment() -> bool:
|
|
14
|
+
"""Return True when the SDK is running under pytest or `PYTEST_*`.
|
|
15
|
+
|
|
16
|
+
The check is deliberately heuristic — it asks "is pytest the entry
|
|
17
|
+
point" by inspecting `sys.modules` and `os.environ`. Callers must not
|
|
18
|
+
use this for security-sensitive branches; it exists only to silence
|
|
19
|
+
diagnostics that would otherwise spam test output.
|
|
20
|
+
"""
|
|
21
|
+
if "pytest" in sys.modules:
|
|
22
|
+
return True
|
|
23
|
+
return "PYTEST_CURRENT_TEST" in os.environ
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: atomicmemory
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python client SDK for AtomicMemory memory and artifact storage.
|
|
5
|
+
Project-URL: Homepage, https://github.com/atomicstrata/atomicmemory-python
|
|
6
|
+
Project-URL: Repository, https://github.com/atomicstrata/atomicmemory-python
|
|
7
|
+
Project-URL: Issues, https://github.com/atomicstrata/atomicmemory-python/issues
|
|
8
|
+
Author: AtomicMemory
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agent,atomicmemory,llm,mem0,memory,rag
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: httpx>=0.27
|
|
25
|
+
Requires-Dist: numpy>=1.26
|
|
26
|
+
Requires-Dist: pydantic>=2.7
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-mock>=3.12; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
33
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
34
|
+
Requires-Dist: vulture>=2.11; extra == 'dev'
|
|
35
|
+
Provides-Extra: embeddings
|
|
36
|
+
Requires-Dist: sentence-transformers>=3.0; extra == 'embeddings'
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# atomicmemory-python
|
|
40
|
+
|
|
41
|
+
Python client SDK for [AtomicMemory](https://github.com/atomicstrata) memory and artifact storage.
|
|
42
|
+
|
|
43
|
+
A backend-agnostic memory and storage client: ingest conversations and documents, search them semantically, package retrieval-ready context, register or upload raw artifacts, and access AtomicMemory-specific features (lifecycle, audit, lessons, agents/trust, runtime config) through typed namespace handles.
|
|
44
|
+
|
|
45
|
+
This is a Python port of the TypeScript [`atomicmemory-sdk`](https://github.com/atomicstrata/atomicmemory-sdk). It mirrors the public surface 1:1 while staying idiomatic to Python (Pydantic models, `httpx` sync + async clients, `match` statements, `snake_case`).
|
|
46
|
+
|
|
47
|
+
## Status
|
|
48
|
+
|
|
49
|
+
Stable release — `1.0.0` on [PyPI](https://pypi.org/project/atomicmemory/).
|
|
50
|
+
|
|
51
|
+
## Quick start
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from atomicmemory import AtomicMemoryClient
|
|
55
|
+
|
|
56
|
+
with AtomicMemoryClient({
|
|
57
|
+
"apiUrl": "http://localhost:3050",
|
|
58
|
+
"apiKey": "server-api-key",
|
|
59
|
+
"userId": "demo",
|
|
60
|
+
}) as client:
|
|
61
|
+
client.memory.initialize()
|
|
62
|
+
|
|
63
|
+
client.memory.ingest({
|
|
64
|
+
"mode": "messages",
|
|
65
|
+
"messages": [
|
|
66
|
+
{"role": "user", "content": "I prefer aisle seats on flights."},
|
|
67
|
+
],
|
|
68
|
+
"scope": {"user": "demo"},
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
page = client.memory.search({"query": "seat preference", "scope": {"user": "demo"}})
|
|
72
|
+
for hit in page.results:
|
|
73
|
+
print(hit.memory.content, hit.score)
|
|
74
|
+
|
|
75
|
+
artifact = client.storage.put({
|
|
76
|
+
"mode": "pointer",
|
|
77
|
+
"uri": "https://example.com/manual.pdf",
|
|
78
|
+
"contentType": "application/pdf",
|
|
79
|
+
})
|
|
80
|
+
print(artifact.artifact_id)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Async usage
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
import asyncio
|
|
87
|
+
from atomicmemory import AsyncAtomicMemoryClient
|
|
88
|
+
|
|
89
|
+
async def main() -> None:
|
|
90
|
+
async with AsyncAtomicMemoryClient({
|
|
91
|
+
"apiUrl": "http://localhost:3050",
|
|
92
|
+
"apiKey": "server-api-key",
|
|
93
|
+
"userId": "demo",
|
|
94
|
+
}) as client:
|
|
95
|
+
await client.memory.initialize()
|
|
96
|
+
results = await client.memory.search({"query": "seat preference", "scope": {"user": "demo"}})
|
|
97
|
+
for hit in results.results:
|
|
98
|
+
print(hit.memory.content)
|
|
99
|
+
|
|
100
|
+
asyncio.run(main())
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## AtomicMemory-specific features
|
|
104
|
+
|
|
105
|
+
When configured with the `atomicmemory` provider, the client exposes a typed handle for backend-specific routes:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
trail = client.memory.atomicmemory.audit.trail(memory_id="mem-123", user_id="demo")
|
|
109
|
+
health = client.memory.atomicmemory.config.health()
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Categories: `lifecycle`, `audit`, `lessons`, `config`, `agents`.
|
|
113
|
+
|
|
114
|
+
## Artifact storage
|
|
115
|
+
|
|
116
|
+
The `client.storage` namespace mirrors the TypeScript SDK's direct storage API:
|
|
117
|
+
|
|
118
|
+
- `capabilities()` reports active backend support.
|
|
119
|
+
- `put({"mode": "pointer", ...})` registers a pointer to caller-owned bytes.
|
|
120
|
+
- `put({"mode": "managed", "body": b"...", ...})` uploads known-length bytes to the configured raw content store.
|
|
121
|
+
- `get`, `get_content`, `head`, `delete`, and `verify` address artifacts by `artifact_id`.
|
|
122
|
+
- `stream_content` streams large artifact bodies without buffering the entire response in memory.
|
|
123
|
+
|
|
124
|
+
Every storage request sends `Authorization: Bearer <apiKey>` and `X-AtomicMemory-User-Id`. The SDK never sends the legacy `?user_id=` URL parameter.
|
|
125
|
+
|
|
126
|
+
## Installation
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pip install atomicmemory # core + local search + SQLite store
|
|
130
|
+
pip install 'atomicmemory[embeddings]' # + sentence-transformers for local embeddings
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Development
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
uv sync --extra dev --extra embeddings
|
|
137
|
+
uv run pytest
|
|
138
|
+
uv run ruff check .
|
|
139
|
+
uv run ruff format --check .
|
|
140
|
+
uv run mypy atomicmemory --strict
|
|
141
|
+
uv run vulture atomicmemory tests .vulture_whitelist.py --min-confidence 90
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
MIT
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
atomicmemory/__init__.py,sha256=dGbYABwc3qpefct9OMCMmYW4kC-dcwrOM229db5heuo,3927
|
|
2
|
+
atomicmemory/_version.py,sha256=qtodX2wTJerDeZidLhVlfcZBglrhPmyrTn5pVe7DZyA,79
|
|
3
|
+
atomicmemory/client/__init__.py,sha256=ZOGuWYtVcnFOtISX5jj9Ii2f4UCPxdNQHqFFbn3Gpho,676
|
|
4
|
+
atomicmemory/client/async_memory_client.py,sha256=DHuMi1gk0u88uy1Vrooy37SzS_tDbizLQTyCRXX73ls,7443
|
|
5
|
+
atomicmemory/client/atomic_memory_client.py,sha256=7LtqEBgVmtmnzhyrMMohweggfMI3nOz6tTSrVcAbbZs,6199
|
|
6
|
+
atomicmemory/client/memory_client.py,sha256=HMzPV_nk_-lAanyg9_0txfbZlemH_fbfbnqYJ7mqI1A,11096
|
|
7
|
+
atomicmemory/core/__init__.py,sha256=YqnArzYJ4xC2xKj7_fob8wlkgf3sj90ugPpBa-2lbr8,897
|
|
8
|
+
atomicmemory/core/errors.py,sha256=rhzK2KV6p7e5lS1oeXbBtevVLn52iPWrZhQ_OKHdgY0,3847
|
|
9
|
+
atomicmemory/core/events.py,sha256=OMoH5SwAkC_BszpvRi9kPQqotQsJA-mVOMLv_Jm2MTM,2124
|
|
10
|
+
atomicmemory/core/logging.py,sha256=bh-I7LMvt2AuGaozYuiPxpzwpLxmdmizhmxd1wdUjGU,1151
|
|
11
|
+
atomicmemory/core/retry.py,sha256=tjes8NP2TwSGqQhvCWbmNnLRDeLGB269fJKfE9Loioc,4234
|
|
12
|
+
atomicmemory/core/validation.py,sha256=pTHBFd6Ksqc0DM6DIIKkJJwoNR5WNKdd4gmU8sZmRks,796
|
|
13
|
+
atomicmemory/embeddings/__init__.py,sha256=bJVq54A_s_TWV-Iim9vXgFtYJsCF3ijZFMcat7G_Dxw,602
|
|
14
|
+
atomicmemory/embeddings/base.py,sha256=gAo8I3euGkQ0_YhIy0a7EwP2PgVq-Ks-2SKU4R6YOiQ,971
|
|
15
|
+
atomicmemory/embeddings/sentence_transformers.py,sha256=_0K8klsV1V4EgAe0e4_PbWME1H7o_f-zrh-f7_0D3xY,3462
|
|
16
|
+
atomicmemory/kv_cache/__init__.py,sha256=pTm1kP-smBuTfSYRcjBQ9zyOYgDIrrNU7NfYG2WO89M,781
|
|
17
|
+
atomicmemory/kv_cache/adapter.py,sha256=BQ3ekePv3W_L7MQJN07IqfSaC-X3aT6BjDzcYTnx8UA,1468
|
|
18
|
+
atomicmemory/kv_cache/memory_storage.py,sha256=HYPV5J9_ShvH6QJcaNp1jBQvwLITJVuTqzqEMDuvqtE,2963
|
|
19
|
+
atomicmemory/kv_cache/sqlite_storage.py,sha256=noMe7OGqMsb0cRimv33UjtQPuNmpHIbF-lEyYluaAjA,4187
|
|
20
|
+
atomicmemory/memory/__init__.py,sha256=5j1vIE-DsO74ZzfKM6TW9aAPAzXCY_APBdbZHTEYsSY,1635
|
|
21
|
+
atomicmemory/memory/filters.py,sha256=7dVi_NQf2uqaftNaSRqFYhxS6FRa-qak1KVs5fLEULU,1568
|
|
22
|
+
atomicmemory/memory/pipeline.py,sha256=LbyufJMmSWVHRJVem_3SpdhWCiL5CGgCP3MkV3BYv1E,1467
|
|
23
|
+
atomicmemory/memory/provider.py,sha256=fZPqRW3rCqIG_oKJs49t0TYjOxawTb_-K_oFqaqIYt8,12619
|
|
24
|
+
atomicmemory/memory/registry.py,sha256=CNbXUPnqRQs7px7JJEvdWcCWazpRLXZiBEgS2tpfd6o,2975
|
|
25
|
+
atomicmemory/memory/service.py,sha256=AxhaMl4vGexJjq_tigoQ44Lheh2KnS6jXnGmNJV-m6U,7879
|
|
26
|
+
atomicmemory/memory/types.py,sha256=6TUYwC0JLGxjMymLyuZWdTa9TLScI4yQDkr36QbFySk,11138
|
|
27
|
+
atomicmemory/providers/__init__.py,sha256=DR8rK2eyn_VIgW3sMHWJnhLtb8W2pbnEajAMRM6jiIk,155
|
|
28
|
+
atomicmemory/providers/atomicmemory/__init__.py,sha256=GL2fdEW8fO4A458IS6cy9NQM3_yTUha-pG9voXNVGHE,1490
|
|
29
|
+
atomicmemory/providers/atomicmemory/agents.py,sha256=rbB0D_8sLDh9oTWth2eGoIdqUjaYRAqEl1V1KClFEYQ,5422
|
|
30
|
+
atomicmemory/providers/atomicmemory/async_handle_impl.py,sha256=2YfIuEiZGmfV2UyhT9HPcDAqi0FZ7f3LI8zaMS_DdUU,8125
|
|
31
|
+
atomicmemory/providers/atomicmemory/async_provider.py,sha256=J3hWUJDftpY7ctzXwueJpFyvxX_lq9B0VL1V7_I3c6c,9671
|
|
32
|
+
atomicmemory/providers/atomicmemory/audit.py,sha256=r8oonF9pZjMDocH0ICBPOb39OE91Hn0cyKKFv6REyfk,2929
|
|
33
|
+
atomicmemory/providers/atomicmemory/config.py,sha256=rt3-xe9hGZLZZw3zMA7CW80vyzFZzPUx6inybDDsRM0,1336
|
|
34
|
+
atomicmemory/providers/atomicmemory/config_handle.py,sha256=DfA81nEecRgRcbGJo7ONLi0zj2nHqbQWh_dI9eWkI4I,4751
|
|
35
|
+
atomicmemory/providers/atomicmemory/handle.py,sha256=cIjMICQCrGCTZFnj2F6iAOipF41bdQbyLI2eO9wnaBk,15361
|
|
36
|
+
atomicmemory/providers/atomicmemory/handle_impl.py,sha256=JoQYgJ1R1jWX_UGrP7Z5LfM5UNWi91RtIVfaDygkCzg,13366
|
|
37
|
+
atomicmemory/providers/atomicmemory/http.py,sha256=XU0NreFhGpseaES5HnFKRZKlfXTktI5a5DxR-QNjT5M,7052
|
|
38
|
+
atomicmemory/providers/atomicmemory/lessons.py,sha256=QnZgti96YdJ05w-1KbT8CPrLnJBI3c0qQ80pD8xO-IA,4512
|
|
39
|
+
atomicmemory/providers/atomicmemory/lifecycle.py,sha256=pX6gZTgeaCDzoSMh6O6K6Lw9tWH-eV4is9U4z_PVaWE,7000
|
|
40
|
+
atomicmemory/providers/atomicmemory/mappers.py,sha256=dsHC9Y0fP2vn83KmN4Aid7wg5Fl2X57EgkTRqSVIW20,4157
|
|
41
|
+
atomicmemory/providers/atomicmemory/path.py,sha256=-99ZiITsu9vYVoOkefMCGDrryNG8N90TwDLi6kz8YRI,538
|
|
42
|
+
atomicmemory/providers/atomicmemory/provider.py,sha256=g87TqZ6hzpTeNOEyW_CtWM3SUfHXsLORXOkem_9-G3k,11467
|
|
43
|
+
atomicmemory/providers/atomicmemory/scope_mapper.py,sha256=ndm6fEptppW6tItDjrzfgOEd1aCAfOUmBwB_5M1VR7E,3610
|
|
44
|
+
atomicmemory/providers/mem0/__init__.py,sha256=U56wstuAuchnPYw-nyLewb3JaHhUVPcqhqVyVhV0EQM,1266
|
|
45
|
+
atomicmemory/providers/mem0/async_provider.py,sha256=moKefYiLRCKDEOfg4U-tF3N3L-CGdPJkQk5BCCJQktU,6910
|
|
46
|
+
atomicmemory/providers/mem0/config.py,sha256=8fOpK19xgqJv4HCeg4HYHNovVKoclG9fvVe2H5XqZgg,1726
|
|
47
|
+
atomicmemory/providers/mem0/http.py,sha256=kDtLLQu6_y1CMMoyv23HxPBbRQ5nyxHriZ1e5_SRGZU,5541
|
|
48
|
+
atomicmemory/providers/mem0/mappers.py,sha256=CRFryLWkRhU_6sGnyrBi25McNjAgitPABks4RFtJCyI,4850
|
|
49
|
+
atomicmemory/providers/mem0/provider.py,sha256=IMnvDI6zegqmC7mhc2laq-NjgQPAjbvOpvSGaRrJmro,7268
|
|
50
|
+
atomicmemory/search/__init__.py,sha256=RD_G1WMR5ae9P2KqGLMrK2IJLatqvFYXxio7hmSESqM,1221
|
|
51
|
+
atomicmemory/search/chunking.py,sha256=rmevW2tuGZjSqHPg0XEkY8Xu4__zQcPH_sMnMhBRwEA,5514
|
|
52
|
+
atomicmemory/search/ranking.py,sha256=AzhyTmO6o0X5W9ORMk-V9Ec-wj4PuO1z-jGZM63GzNk,2922
|
|
53
|
+
atomicmemory/search/semantic_search.py,sha256=tJizviYA7Ewo3WSg0H1RO-jaSSXm6gR4AoDlyafptfw,4741
|
|
54
|
+
atomicmemory/search/similarity.py,sha256=8sTcnt1NecWEYRNPcfNfy6E0PRLanqUH-GhHutUe5OI,3602
|
|
55
|
+
atomicmemory/storage/__init__.py,sha256=fGZBT15cjm6TCyJby19vAmpHpyGOmv-fNkhnhZvbLq4,1684
|
|
56
|
+
atomicmemory/storage/_mapping.py,sha256=xS9CVFHmW3YLG2nXvSI8Sn39DwdfCa3kvt4teBlY4Xo,11841
|
|
57
|
+
atomicmemory/storage/async_client.py,sha256=6x0RW8uhepvUVU_pj3Izsaf3dtA0DbnQWMWurNFJoqI,7452
|
|
58
|
+
atomicmemory/storage/client.py,sha256=s78u-pGVG6DtWVPr8gwqryPLvMHeOT1xwT9KQwtuXek,12473
|
|
59
|
+
atomicmemory/storage/errors.py,sha256=3R8vbGfW_8RaFlYIZ5oAxrdVKqih34JVtshi-LYQdNU,3790
|
|
60
|
+
atomicmemory/storage/types.py,sha256=uzUP5NEKHYbVSJ-ljcsdZ5WKp2WOOO4avwKcTPepIK0,11030
|
|
61
|
+
atomicmemory/utils/__init__.py,sha256=RqKXEYX5ZNHdTOt_NOY7B1DU1VsiUDak1CL3YnDOCAU,149
|
|
62
|
+
atomicmemory/utils/environment.py,sha256=vTyN_opmNtfur9rsjGdXGSpouNT3MckUgTm7Voe7Qmw,723
|
|
63
|
+
atomicmemory/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
64
|
+
atomicmemory-1.0.0.dist-info/METADATA,sha256=NteFycOA0bUbVOut2QbxYXht0EOT3N5Kg9RCSjoCOMg,5226
|
|
65
|
+
atomicmemory-1.0.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
66
|
+
atomicmemory-1.0.0.dist-info/licenses/LICENSE,sha256=vMGL9gR35PGpiGIytzTt1H2uHZLO3N_bPAMu_Uk5pR0,1069
|
|
67
|
+
atomicmemory-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AtomicMemory
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|