All notable changes to atomicmemory will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Add framework-neutral
memory_toolsandasync_memory_toolsfactories with fixed application user scope, strict argument schemas, bounded retrieval output, and safe model-facing errors. - Reject HTTP 202 ingest responses with
PendingIngestErrorinstead of returning an empty terminal result. Pending or failed writes must not be retried blindly. - Add a sync/async tools example and real-HTTP contract verification.
- Encode explicit
content_classon verbatim ingest in the v1 contract codec. Text and messages modes still reject the field because the v1 wire contract does not expose it on those modes. No content class is inferred or defaulted. - Refresh the vendored contract schema and provenance to include the verbatim content-class field.
- Refresh the development/source lockfile past the reported AnyIO, idna, setuptools, Transformers, and Torch advisory ranges. This updates the locked environment, not the SDK's dependency constraints; existing installations should also update their dependencies.
api_urlis now validated against SSRF across all six SDK configs (the three provider configs, the storage/client configs, andEntitiesClientConfig) via one shared validator. It always rejects link-local / cloud-metadata addresses (AWS IMDS169.254.169.254, IPv6fe80::/10) — including their decimal (http://2852039166/), hex, octal, short-form, and IPv4-mapped-IPv6 (::ffff:169.254.169.254) encodings, which are canonicalized so they cannot bypass the guard. Loopback / private / reserved IP literals remain allowed by default — the SDK routinely connects to local and self-hosted cores — and are rejected only when you opt into strict mode withallowPrivateNetworks=False. Hostnames (incl. thelocalhostdefault) are intentionally not DNS-resolved at config time. This matches the Node SDK's posture for cross-SDK parity, and a reflective enumeration test fails if a newapi_urlconfig omits the guard. (FailSafe AGNT-PY-001.)
UnsupportedOperationError(subclass ofProviderError) andInvalidScopeError(subclass ofValidationError), raised where those parents were previously raised bare: a provider missing thepackageextension, and an operation missing required scope fields. Existingexcept ProviderError/except ValidationErrorhandlers keep working; consumers can now catch the specific types, matching the TS SDK. Exported from the package root.AsyncMemoryProcessingPipeline+NOOP_ASYNC_PIPELINE(exported fromatomicmemory.memoryalongside the existing sync type): the async-surface pipeline type used byAsyncProviderRegistration.EntitiesClient/AsyncEntitiesClient: theentitiesnamespace over/v1/entities, ported from the TS SDK — entity profiles, listing, detail, cascade delete, attribute triples, per-memory history, per-entity settings patching, and entity merge. Wired intoAtomicMemoryClient/AsyncAtomicMemoryClientas.entitieson the same transport config, closed with the client. Python field names match the snake_case wire directly (the TS camelCase mapping layer has no Python counterpart).
- Registered memory pipelines now actually execute:
MemoryService/AsyncMemoryServicerunpreprocess_ingest(which may split one input into many; per-item results merge in order),postprocess_ingest,preprocess_search/postprocess_search(postprocess receives the processed request),preprocess_get/postprocess_get, andpostprocess_list, matching the TSMemoryServicesemantics.deleteandpackagetake no pipeline. Before 1.1.1 these hooks were accepted at registration but never invoked. Hook exceptions propagate unwrapped — hooks are caller-supplied code. MemoryProcessingPipelinehook signatures are now synchronous (the async surface usesAsyncMemoryProcessingPipeline). Type-hint change only for code that constructed pipelines — which received no behavior before this release.
atomicmemory.contract.v1: a wire codec for the v1 provider contract's deliberately mixed-case encoding (Memory.createdAt/updatedAtandSearchResult.rankingScoreare camelCase on the wire;version_id,observed_at, and retrieval-receipt fields are snake_case). Encode/decode helpers coverMemory,Provenance,SearchResult,SearchResultPage,SearchRequest, and ingest payloads (IngestInput,IngestResult). Dates follow the contract's ISO-8601 UTC millisecondZform (_to_iso_z, equivalent to TStoISOString()). Naive datetimes in encode paths are assumed UTC.encode_ingest_inputfails closed on the Python-aheadcontent_classfield (no place in the v1additionalProperties: falseschemas; TS contract alignment is a recorded follow-up). Explicit-nullversion_idinSearchResultnormalizes to absent on re-encode, matching the TS optional declaration.encode_search_requestusesby_alias=Trueso Python-keyword-safe combinator field names (and_/or_/not_) emit their wire aliases; a recursive_jsonifywalk converts anydatetimeoperands in filter trees to the toISOString form. In-process models and provider mappers are unchanged.- Vendored the TS SDK's versioned v1 wire contract (JSON Schemas, cross-provider conformance corpus, and CONTRACT.md) under
contract/, with explicit provenance incontract/VENDORED.jsonand a documented refresh script (scripts/refresh_contract.py, never run in CI). A pytest conformance harness proves corpus fixtures decode into the Python models (directly for snake-on-wire types, through the codec for the mixed-case search response) and that SDK emissions validate against the vendored draft-2020-12 schemas, with the TS suite's negative cases mirrored against both schemas and Pydantic. Thecapabilities-descriptorcase is schema-only (no Python model in this release — recorded follow-up). atomicmemory.contractre-exportsv1as a specialty import surface; deliberately not re-exported from the package root to keep the root namespace focused on the core provider API.AsyncProviderFactorynow accepts factories that return anAwaitable[AsyncProviderRegistration], enabling lazy or async provider construction duringAsyncMemoryService.initialize().MemoryService.initialize()andAsyncMemoryService.initialize()raiseConfigErrorwhen the configured default provider has no registered factory, making a misconfigured default an immediate, explicit error rather than a silent no-op.
content_classis now accepted on every ingest mode (text,messages, andverbatim), not justverbatim, and is forwarded to core for all modes. Extraction-based ingests (text/messages) can now satisfy a core running the defaultRAW_CONTENT_POLICY=reject. Still never defaulted — omitting it leaves the field off the wire and a reject-policy core fails closed.- Both clients'
initialize()is now concurrency-safe and idempotent: concurrent callers share a single initialization run (the first caller's registry wins), and the completed outcome — success or failure — is captured in loop-independent state forAsyncMemoryClient. - A failed
initialize()is sticky: retrying re-raises the original error from any caller; resolve the cause and construct a new client rather than retrying on the same instance. AsyncMemoryClient.initialize()shields each waiter from cancellation so that one waiter's timeout or cancellation never cancels the shared run for other concurrent callers.AsyncMemoryClient.close()during a pending initialization cancels the shared run; staged providers are torn down by the service's atomic-initialize cleanup, any concurrentinitialize()waiter receivesCancelledError, and the client ends in the not-initialized state without recording a sticky error.- Both
MemoryServiceandAsyncMemoryServicestage provider registrations atomically: factories and providerinitialize()calls run against a local staging area, and the maps are replaced only after every provider succeeds; on any failure, already-staged providers are torn down best-effort before the original error re-raises. MemoryService.close()andAsyncMemoryService.close()are best-effort: every provider gets a chance to close regardless of earlier failures, maps are cleared in afinallyblock, and the first failure is re-raised after all providers have been given the chance to close.
atomicmemory.__version__reported1.0.0while package metadata said1.0.1; all version sources now agree at1.1.0, guarded by a regression test that will fail if they drift again.
- Version bump for public package publication after internal-to-public repository sync.
Initial public stable release.
AtomicMemoryClientandAsyncAtomicMemoryClientas the primary public client surfaces.- Memory ingestion, search, package, get, list, and delete support.
- AtomicMemory, Mem0, and Hindsight provider adapters.
- Typed AtomicMemory namespace handles for lifecycle, audit, lessons, agents, and runtime config.
- Direct artifact storage client with pointer and managed artifact workflows.
- Local embedding, semantic search, and KV cache helpers.
- Pydantic models, typed exceptions, and
py.typedmarker for downstream type checkers.