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.
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.