From e16c492eb1eb3ae5cf26103a6e578cd51a9d0d05 Mon Sep 17 00:00:00 2001 From: Shanu Date: Tue, 18 Aug 2026 18:22:35 +0530 Subject: [PATCH 1/2] =?UTF-8?q?Select=20an=20engine=20by=20feature=20(#18?= =?UTF-8?q?=20=C2=A7D1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the per-engine features §D1 asks for -- `tinycortex`, `supermemory`, `mem0`, `cognee`, and the `memory-git` capability add-on -- so a host names an engine instead of taking a second dependency on an adapter crate: tinymemory = { version = "1", features = ["tinycortex"] } and `tinymemory::tinycortex::provider(backend)` binds it. §D1's snippet could not be written as given ------------------------------------------- `tinycortex = ["dep:tinymemory-tinycortex", ...]` on this crate is a package cycle, which cargo rejects: tinymemory -> tinymemory-tinycortex -> tinymemory-core -> tinymemory Three edges had to go, and each is worth knowing: 1. The adapters depended on this crate for `mandatory::MemoryTraitProvider`. That module moved to `tinymemory-api`. It costs the contract crate nothing -- it names only `async_trait`, `std`, and contract types -- and the contract is where a composition over `traits::Memory` belongs anyway. 2. The adapters depended on this crate for the reserved driver ids. Those moved to `tinymemory_api::drivers`, following the precedent that `NULL_DRIVER_ID` already lived in the contract. Reserving a name there does not teach the contract about the engine: admission still decides the class, in this crate's registry, where the trust decision belongs. 3. `tinymemory-core` declared a dependency on this crate and used nothing from it. That dead declaration is what actually closed the cycle. Both moves are re-exported, so `tinymemory::mandatory::MemoryTraitProvider` and `tinymemory::registry::TINYCORTEX_DRIVER_ID` still resolve. That is load-bearing rather than tidy: OpenCompany imports the first of those. What it costs, measured ----------------------- default / none 47 crates supermemory 133 supermemory,mem0,cognee 133 (one adapter serves all three) tinycortex 224 memory-git 228 Nothing links an engine until one is named. Two incidental fixes the move forced: `tokio` becomes a dev-dependency of `tinymemory-api` (the moved tests are async -- dev-only, so §D4's forbidden-dependency rule is untouched), and the moved module's `//!` doc links need explicit paths where its `///` item docs resolve bare. cargo fmt --all -- --check: clean cargo clippy --workspace --all-targets: clean RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features: clean cargo test --workspace: 1206 passed, 0 failed -- identical to main, so the module move lost no tests cargo check -p tinymemory --features {tinycortex,supermemory,mem0,cognee,memory-git}: 0 errors each --- Cargo.lock | 14 ++------- Cargo.toml | 25 ++++++++++++++++ adapters/remote/Cargo.toml | 1 - adapters/remote/src/cognee.rs | 2 +- adapters/remote/src/lib.rs | 4 +-- adapters/remote/src/mem0.rs | 2 +- adapters/remote/src/supermemory.rs | 2 +- adapters/tinycortex/Cargo.toml | 1 - adapters/tinycortex/src/engine/mod.rs | 2 +- adapters/tinycortex/src/lib.rs | 6 ++-- api/Cargo.toml | 4 +++ api/src/drivers.rs | 30 +++++++++++++++++++ api/src/lib.rs | 12 ++++++++ {src => api/src}/mandatory/mod.rs | 40 +++++++++++++------------- {src => api/src}/mandatory/provider.rs | 28 +++++++++--------- {src => api/src}/mandatory/test.rs | 18 ++++++------ core/Cargo.toml | 1 - src/lib.rs | 26 ++++++++++++++++- src/registry/mod.rs | 24 +++++++--------- 19 files changed, 161 insertions(+), 81 deletions(-) create mode 100644 api/src/drivers.rs rename {src => api/src}/mandatory/mod.rs (88%) rename {src => api/src}/mandatory/provider.rs (87%) rename {src => api/src}/mandatory/test.rs (97%) diff --git a/Cargo.lock b/Cargo.lock index 0c5ca9c..ca6cd55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1788,15 +1788,7 @@ dependencies = [ name = "tinycortex-api" version = "0.1.1" dependencies = [ - "anyhow", - "async-trait", - "chrono", - "serde", - "serde_json", - "sha2 0.10.9", - "thiserror 2.0.20", "tinymemory-api", - "uuid", ] [[package]] @@ -1810,7 +1802,9 @@ dependencies = [ "serde_json", "tinymemory-api", "tinymemory-conformance", + "tinymemory-remote", "tinymemory-sync", + "tinymemory-tinycortex", "tokio", ] @@ -1827,6 +1821,7 @@ dependencies = [ "serde_json", "sha2 0.11.0", "thiserror 2.0.20", + "tokio", "toml 0.9.12+spec-1.1.0", "uuid", ] @@ -1866,7 +1861,6 @@ dependencies = [ "tinyagents", "tinycortex", "tinycortex-api", - "tinymemory", "tinymemory-api", "tinymemory-sync", "tokio", @@ -1887,7 +1881,6 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.9", - "tinymemory", "tinymemory-api", "tinymemory-conformance", "tokio", @@ -1914,7 +1907,6 @@ dependencies = [ "serde", "serde_json", "tinycortex", - "tinymemory", "tinymemory-api", "tinymemory-conformance", "tinymemory-core", diff --git a/Cargo.toml b/Cargo.toml index 5b33af5..132779b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,16 @@ exclude = [ # one dependency rather than two, and so `tinymemory::MemoryProvider` and # `tinymemory_api::provider::MemoryProvider` are the same type. tinymemory-api = { path = "api" } +# The engines, each behind its own feature (#18 §D1). Optional, so the default +# build is still the contract, the registry and the mandatory composition and +# nothing that links C. +# +# This direction only became legal once `mandatory` and the reserved driver ids +# moved into `tinymemory-api`: the adapters used to depend on this crate for +# them, and a facade depending back on the adapters is a package cycle cargo +# forbids. +tinymemory-tinycortex = { path = "adapters/tinycortex", optional = true } +tinymemory-remote = { path = "adapters/remote", optional = true } # The mandatory capability families are `async fn`s on object-safe traits. async-trait = "0.1" # `Memory` is anyhow-typed; `mandatory::engine_error` maps it onto `MemoryError`. @@ -85,8 +95,23 @@ tinymemory-conformance = { path = "conformance" } tinymemory-sync = { path = "sync" } [features] +# Nothing by default. A host that names no engine links no engine. default = [] +# --- Engines --------------------------------------------------------------- +# Each pulls exactly the adapter that serves it. `supermemory`, `mem0` and +# `cognee` share one adapter crate, so enabling several costs one dependency +# rather than three. +tinycortex = ["dep:tinymemory-tinycortex"] +supermemory = ["dep:tinymemory-remote"] +mem0 = ["dep:tinymemory-remote"] +cognee = ["dep:tinymemory-remote"] + +# --- Capability add-ons ---------------------------------------------------- +# Each requires the engine that serves it, so asking for a capability cannot +# produce a build where nothing implements it. +memory-git = ["tinycortex", "tinymemory-tinycortex/memory-git"] + # Lints apply to this package only, deliberately. `api/` is contract code moved # verbatim from `tinycortex-api` and is held byte-identical; subjecting it to a # stricter lint set than it was written under would force cosmetic edits through diff --git a/adapters/remote/Cargo.toml b/adapters/remote/Cargo.toml index 3bb4da5..2690528 100644 --- a/adapters/remote/Cargo.toml +++ b/adapters/remote/Cargo.toml @@ -10,7 +10,6 @@ repository = "https://github.com/tinyhumansai/tinymemory" [dependencies] # The engine-neutral contract and mandatory-family composition. -tinymemory = { path = "../.." } tinymemory-api = { path = "../../api" } # Memory is an object-safe async trait and each native HTTP dialect is async. async-trait = "0.1" diff --git a/adapters/remote/src/cognee.rs b/adapters/remote/src/cognee.rs index 6b2a60d..e0bb8fc 100644 --- a/adapters/remote/src/cognee.rs +++ b/adapters/remote/src/cognee.rs @@ -11,7 +11,7 @@ use tinymemory_api::types::MemoryTaint; use crate::common::{stable_id, Dialect, HttpClient, RemoteMemory, StoredEntry}; /// Stable driver id used by configuration and status output. -pub use tinymemory::registry::COGNEE_DRIVER_ID; +pub use tinymemory_api::drivers::COGNEE_DRIVER_ID; /// Default base URL for Cognee's managed API. pub const COGNEE_API_ENDPOINT: &str = "https://api.cognee.ai"; diff --git a/adapters/remote/src/lib.rs b/adapters/remote/src/lib.rs index 1b9d559..70ab990 100644 --- a/adapters/remote/src/lib.rs +++ b/adapters/remote/src/lib.rs @@ -3,7 +3,7 @@ //! The adapters preserve TinyMemory's exact `(namespace, key)` upsert contract //! in backend metadata while delegating semantic recall to each engine's native //! search API. They advertise Core, Recall, and Portability through -//! [`tinymemory::mandatory::MemoryTraitProvider`]. +//! [`tinymemory_api::mandatory::MemoryTraitProvider`]. //! //! Credentials are accepted only at construction and are never exposed by //! `Debug` implementations or error messages. @@ -19,7 +19,7 @@ pub use supermemory::{SupermemoryMemory, SUPERMEMORY_API_ENDPOINT, SUPERMEMORY_D use std::sync::Arc; -use tinymemory::mandatory::MemoryTraitProvider; +use tinymemory_api::mandatory::MemoryTraitProvider; /// Wrap a Supermemory HTTP backend as a bound TinyMemory provider. #[must_use] diff --git a/adapters/remote/src/mem0.rs b/adapters/remote/src/mem0.rs index 53221d9..d92546d 100644 --- a/adapters/remote/src/mem0.rs +++ b/adapters/remote/src/mem0.rs @@ -11,7 +11,7 @@ use tinymemory_api::types::MemoryTaint; use crate::common::{category, Dialect, HttpClient, RemoteMemory, StoredEntry}; /// Stable driver id used by configuration and status output. -pub use tinymemory::registry::MEM0_DRIVER_ID; +pub use tinymemory_api::drivers::MEM0_DRIVER_ID; /// A self-hosted Mem0 server exposed through TinyMemory's storage contract. #[derive(Debug)] diff --git a/adapters/remote/src/supermemory.rs b/adapters/remote/src/supermemory.rs index d69c599..d1c70d0 100644 --- a/adapters/remote/src/supermemory.rs +++ b/adapters/remote/src/supermemory.rs @@ -10,7 +10,7 @@ use tinymemory_api::types::MemoryTaint; use crate::common::{category, stable_id, Dialect, HttpClient, RemoteMemory, StoredEntry}; /// Stable driver id used by configuration and status output. -pub use tinymemory::registry::SUPERMEMORY_DRIVER_ID; +pub use tinymemory_api::drivers::SUPERMEMORY_DRIVER_ID; /// Default base URL for Supermemory's managed API. pub const SUPERMEMORY_API_ENDPOINT: &str = "https://api.supermemory.ai"; diff --git a/adapters/tinycortex/Cargo.toml b/adapters/tinycortex/Cargo.toml index 73ba1e7..ce0b7c3 100644 --- a/adapters/tinycortex/Cargo.toml +++ b/adapters/tinycortex/Cargo.toml @@ -13,7 +13,6 @@ repository = "https://github.com/tinyhumansai/tinymemory" [dependencies] # The contract this adapter targets. -tinymemory = { path = "../.." } tinymemory-api = { path = "../../api" } # The engine being adapted. A version requirement rather than a path, so a host # that already pins its own TinyCortex checkout unifies both onto one copy diff --git a/adapters/tinycortex/src/engine/mod.rs b/adapters/tinycortex/src/engine/mod.rs index ebfe0eb..a9a2c25 100644 --- a/adapters/tinycortex/src/engine/mod.rs +++ b/adapters/tinycortex/src/engine/mod.rs @@ -21,7 +21,6 @@ use std::sync::Arc; use crate::TinycortexMemory; use async_trait::async_trait; use chrono::Utc; -use tinymemory::mandatory::MemoryTraitProvider; use tinymemory_api::capabilities::Capabilities; use tinymemory_api::chunks::Chunk; use tinymemory_api::error::MemoryError; @@ -31,6 +30,7 @@ use tinymemory_api::host::{ CloudProviderCreds, ComposioMode, LocalAiConfig, MemoryConfig, MemoryHostConfig, MemoryTreeConfig, SchedulerGateConfig, }; +use tinymemory_api::mandatory::MemoryTraitProvider; use tinymemory_api::provider::types::{ EntityHit, EntityRef, ExportPage, ExportRecord, ImportOutcome, IngestItem, IngestOutcome, MaintenanceReport, SourceItem, SourceScope, diff --git a/adapters/tinycortex/src/lib.rs b/adapters/tinycortex/src/lib.rs index fba0063..57ae0bf 100644 --- a/adapters/tinycortex/src/lib.rs +++ b/adapters/tinycortex/src/lib.rs @@ -55,14 +55,14 @@ pub use memory::TinycortexMemory; use std::sync::Arc; -use tinymemory::mandatory::MemoryTraitProvider; +use tinymemory_api::mandatory::MemoryTraitProvider; /// The driver id this adapter binds under. /// -/// Matches [`tinymemory::registry::TINYCORTEX_DRIVER_ID`], which is where +/// Matches [`tinymemory_api::drivers::TINYCORTEX_DRIVER_ID`], which is where /// admission reserves it — the constant lives there so a host that compiles /// this adapter out still refuses to bind something else under the name. -pub use tinymemory::registry::TINYCORTEX_DRIVER_ID; +pub use tinymemory_api::drivers::TINYCORTEX_DRIVER_ID; /// Wrap a TinyCortex backend as a bound memory driver. /// diff --git a/api/Cargo.toml b/api/Cargo.toml index 3d5f32d..8031c85 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -61,6 +61,10 @@ uuid = { version = "1", features = ["v4"] } # The moved `host::` config sections are parsed from TOML in their own tests, # exactly as the host parses them from `config.toml`. toml = "0.9" +# The mandatory-composition tests are async — they drive a `MemoryProvider`. +# Dev-only, so it does not touch the forbidden-dependency rule this crate's +# manifest enforces for its normal graph (#18 §D4). +tokio = { version = "1", features = ["macros", "rt"] } [features] default = [] diff --git a/api/src/drivers.rs b/api/src/drivers.rs new file mode 100644 index 0000000..71bf981 --- /dev/null +++ b/api/src/drivers.rs @@ -0,0 +1,30 @@ +//! The reserved driver ids. +//! +//! These name the engines this workspace ships. They live in the contract crate +//! rather than in the facade's registry for the same reason +//! [`crate::null::NULL_DRIVER_ID`] already did: an adapter has to spell the id +//! it binds under, and reaching into the facade for it made every adapter +//! depend on the facade — which in turn made the facade unable to depend on the +//! adapters, a package cycle cargo forbids. That cycle is what blocked #18 +//! §D1's per-engine features. +//! +//! Reserving them here does **not** mean the contract knows about these +//! engines. It knows their *names*, so that admission can refuse something else +//! binding under one — a host that compiles an adapter out must still reject an +//! impostor claiming its id. The class each id is admitted under stays in the +//! facade's registry, where the trust decision belongs. +//! +//! `tinymemory::registry` re-exports all of these, so existing paths resolve +//! unchanged. + +/// The driver id of the bundled TinyCortex embedded engine. +pub const TINYCORTEX_DRIVER_ID: &str = "tinycortex"; + +/// Driver id of the native Supermemory HTTP adapter. +pub const SUPERMEMORY_DRIVER_ID: &str = "supermemory"; + +/// Driver id of the native Mem0 HTTP adapter. +pub const MEM0_DRIVER_ID: &str = "mem0"; + +/// Driver id of the native Cognee HTTP adapter. +pub const COGNEE_DRIVER_ID: &str = "cognee"; diff --git a/api/src/lib.rs b/api/src/lib.rs index f34647a..bf237aa 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -66,10 +66,22 @@ pub mod capabilities; pub mod chunks; +pub mod drivers; pub mod error; pub mod goals; pub mod health; pub mod host; +/// The mandatory-family composition: wrap any [`traits::Memory`] backend as a +/// complete [`provider::MemoryProvider`]. +/// +/// Lives here rather than in the `tinymemory` facade because every adapter +/// needs it, and an adapter that reached for it in the facade made the facade +/// unable to depend on adapters in turn — a package cycle cargo forbids, and +/// the reason #18 §D1's engine features could not be declared. It costs this +/// crate nothing: the module names only `async_trait`, `std`, and this crate's +/// own contract types. The facade re-exports it, so `tinymemory::mandatory` +/// keeps resolving. +pub mod mandatory; pub mod null; pub mod provider; pub mod recall; diff --git a/src/mandatory/mod.rs b/api/src/mandatory/mod.rs similarity index 88% rename from src/mandatory/mod.rs rename to api/src/mandatory/mod.rs index 1e4fa0a..578fc9d 100644 --- a/src/mandatory/mod.rs +++ b/api/src/mandatory/mod.rs @@ -1,34 +1,34 @@ //! The three mandatory capability families, composed over the storage trait. //! -//! [`MemoryCore`](tinymemory_api::provider::MemoryCore), [`MemoryRecall`](tinymemory_api::provider::MemoryRecall) and [`MemoryPortability`](tinymemory_api::provider::MemoryPortability) are supertraits of -//! [`MemoryProvider`](tinymemory_api::provider::MemoryProvider): a driver +//! [`MemoryCore`](crate::provider::MemoryCore), [`MemoryRecall`](crate::provider::MemoryRecall) and [`MemoryPortability`](crate::provider::MemoryPortability) are supertraits of +//! [`MemoryProvider`](crate::provider::MemoryProvider): a driver //! missing any of them cannot be constructed at all. For a backend that already -//! implements [`Memory`], almost all three are mechanical — and the parts that +//! implements [`Memory`](crate::traits::Memory), almost all three are mechanical — and the parts that //! are *not* mechanical are the parts every such backend gets wrong the same //! way. So they live here once rather than in each driver. //! //! ## The four things that are not a straight delegation //! -//! 1. **`store` maps onto [`Memory::store_with_taint`], never [`Memory::store`].** -//! The contract's `store` always carries a [`MemoryTaint`](tinymemory_api::types::MemoryTaint), because +//! 1. **`store` maps onto [`Memory::store_with_taint`](crate::traits::Memory::store_with_taint), never [`Memory::store`](crate::traits::Memory::store).** +//! The contract's `store` always carries a [`MemoryTaint`](crate::types::MemoryTaint), because //! provenance is stamped by the host's policy layer *before* the call. -//! [`Memory::store`] hard-codes [`MemoryTaint::Internal`](tinymemory_api::types::MemoryTaint::Internal), so routing through +//! [`Memory::store`](crate::traits::Memory::store) hard-codes [`MemoryTaint::Internal`](crate::types::MemoryTaint::Internal), so routing through //! it would launder externally-sourced content into internal-trust content — //! the one failure mode a provenance guard exists to prevent. Note -//! [`Memory::store_with_taint`]'s *trait default* also silently drops the +//! [`Memory::store_with_taint`](crate::traits::Memory::store_with_taint)'s *trait default* also silently drops the //! taint, so a backend that does not override it is unsafe here; that is a //! backend bug, not something this layer can paper over. //! //! 2. **`list(None, ..)` spans every namespace.** The contract says an -//! all-`None` list returns everything the driver holds. A typical [`Memory`] +//! all-`None` list returns everything the driver holds. A typical [`Memory`](crate::traits::Memory) //! implementation normalises a `None` namespace to -//! [`GLOBAL_NAMESPACE`], so a naive delegation returns one namespace and -//! calls it "everything". [`list_everything`] composes `namespace_summaries` +//! [`GLOBAL_NAMESPACE`](crate::types::GLOBAL_NAMESPACE), so a naive delegation returns one namespace and +//! calls it "everything". [`list_everything`](crate::mandatory::list_everything) composes `namespace_summaries` //! with a per-namespace `list` instead. //! //! 3. **A scoped recall is refused, not ignored.** See [`recall`]. //! -//! 4. **Import must not re-stamp provenance.** See [`import_records`]. +//! 4. **Import must not re-stamp provenance.** See [`import_records`](crate::mandatory::import_records). //! //! ## Why free functions rather than a blanket impl //! @@ -36,14 +36,14 @@ //! driver that wants to override one method, and would force every driver to //! resolve its handle through one shape. These are plain functions taking //! `&dyn Memory`, so a driver delegates the parts it wants and keeps its own -//! logging, laziness, and error context. [`MemoryTraitProvider`] is the +//! logging, laziness, and error context. [`MemoryTraitProvider`](crate::mandatory::MemoryTraitProvider) is the //! batteries-included alternative for a backend that wants all three whole. -use tinymemory_api::error::MemoryError; -use tinymemory_api::provider::types::{ExportPage, ExportRecord, ImportOutcome, SourceScope}; -use tinymemory_api::recall::OwnedRecallOpts; -use tinymemory_api::traits::Memory; -use tinymemory_api::types::{MemoryCategory, MemoryEntry, RecallOpts, GLOBAL_NAMESPACE}; +use crate::error::MemoryError; +use crate::provider::types::{ExportPage, ExportRecord, ImportOutcome, SourceScope}; +use crate::recall::OwnedRecallOpts; +use crate::traits::Memory; +use crate::types::{MemoryCategory, MemoryEntry, RecallOpts, GLOBAL_NAMESPACE}; mod provider; @@ -168,7 +168,7 @@ fn parse_cursor(cursor: Option<&str>) -> Result<(usize, usize), MemoryError> { /// Renders one entry as an export record. /// -/// A record round-trips the five fields [`MemoryCore`](tinymemory_api::provider::MemoryCore) +/// A record round-trips the five fields [`MemoryCore`](crate::provider::MemoryCore) /// owns — `key`, `content`, `category`, `session_id`, `taint` — plus its /// namespace and timestamp. Document-tier attributes (`title`, `tags`, /// `metadata`, `source_type`, `priority`) belong to the `Documents` family and @@ -332,10 +332,10 @@ pub async fn export_page( /// `MemoryPortability::import_records` over a [`Memory`] backend. /// -/// Each record is stored with its **own** [`MemoryTaint`](tinymemory_api::types::MemoryTaint) via +/// Each record is stored with its **own** [`MemoryTaint`](crate::types::MemoryTaint) via /// [`Memory::store_with_taint`]: an importing driver must persist the /// provenance it is given and must not re-stamp it. [`Memory::store`] would -/// stamp [`MemoryTaint::Internal`](tinymemory_api::types::MemoryTaint::Internal), quietly upgrading the trust of every +/// stamp [`MemoryTaint::Internal`](crate::types::MemoryTaint::Internal), quietly upgrading the trust of every /// externally-sourced record in a restore. /// /// Per-record rejection is reported in [`ImportOutcome`], never fatal: a diff --git a/src/mandatory/provider.rs b/api/src/mandatory/provider.rs similarity index 87% rename from src/mandatory/provider.rs rename to api/src/mandatory/provider.rs index 4964bb3..5eee27f 100644 --- a/src/mandatory/provider.rs +++ b/api/src/mandatory/provider.rs @@ -1,12 +1,12 @@ -//! [`MemoryTraitProvider`] — a complete, mandatory-only -//! [`MemoryProvider`](tinymemory_api::provider::MemoryProvider) over any -//! [`Memory`] backend. +//! [`MemoryTraitProvider`](crate::mandatory::MemoryTraitProvider) — a complete, mandatory-only +//! [`MemoryProvider`](crate::provider::MemoryProvider) over any +//! [`Memory`](crate::traits::Memory) backend. //! //! ## What this is for //! //! Two things, and it is worth being clear which is which. //! -//! **A real driver for a simple backend.** A store that implements [`Memory`] +//! **A real driver for a simple backend.** A store that implements [`Memory`](crate::traits::Memory) //! becomes a bindable memory driver by wrapping it here — no capability //! plumbing, no export format to invent. It advertises exactly the three //! mandatory families, so a host binding it gets a memory subsystem whose @@ -21,7 +21,7 @@ //! No optional families. Every `as_*` accessor keeps the contract's `None` //! default, and [`capabilities`](MemoryTraitProvider::capabilities) reports the //! mandatory three — so the two halves agree and -//! [`audit_provider`](tinymemory_api::provider::audit_provider) passes. A driver +//! [`audit_provider`](crate::provider::audit_provider) passes. A driver //! that wants documents, trees, or a diff ledger implements those families over //! its own engine and delegates only the mandatory three here. //! @@ -30,19 +30,19 @@ use std::sync::Arc; +use crate::capabilities::{Capabilities, Capability}; +use crate::error::MemoryError; +use crate::health::MemoryHealth; +use crate::provider::types::{ExportPage, ExportRecord, ImportOutcome, SourceScope}; +use crate::provider::{MemoryCore, MemoryPortability, MemoryProvider, MemoryRecall}; +use crate::recall::OwnedRecallOpts; +use crate::traits::Memory; +use crate::types::{MemoryCategory, MemoryEntry, MemoryTaint, NamespaceSummary}; use async_trait::async_trait; -use tinymemory_api::capabilities::{Capabilities, Capability}; -use tinymemory_api::error::MemoryError; -use tinymemory_api::health::MemoryHealth; -use tinymemory_api::provider::types::{ExportPage, ExportRecord, ImportOutcome, SourceScope}; -use tinymemory_api::provider::{MemoryCore, MemoryPortability, MemoryProvider, MemoryRecall}; -use tinymemory_api::recall::OwnedRecallOpts; -use tinymemory_api::traits::Memory; -use tinymemory_api::types::{MemoryCategory, MemoryEntry, MemoryTaint, NamespaceSummary}; use super::{engine_error, export_page, import_records, list_everything, recall}; -/// A mandatory-only memory driver over an [`Memory`] backend. +/// A mandatory-only memory driver over an [`Memory`](crate::traits::Memory) backend. #[derive(Clone)] pub struct MemoryTraitProvider { memory: Arc, diff --git a/src/mandatory/test.rs b/api/src/mandatory/test.rs similarity index 97% rename from src/mandatory/test.rs rename to api/src/mandatory/test.rs index 704f535..1f7e818 100644 --- a/src/mandatory/test.rs +++ b/api/src/mandatory/test.rs @@ -1,6 +1,6 @@ //! Tests for the shared mandatory-family logic. //! -//! These run against [`VecMemory`], a deliberately dumb in-process [`Memory`] +//! These run against [`VecMemory`], a deliberately dumb in-process [`Memory`](crate::traits::Memory) //! backend defined here rather than borrowed from an engine crate: the point of //! this module is that the logic is engine-neutral, and a test that needed a //! real engine would not demonstrate that. @@ -12,7 +12,7 @@ use std::collections::BTreeMap; use std::sync::Mutex; -use tinymemory_api::provider::audit_provider; +use crate::provider::audit_provider; use super::*; @@ -46,8 +46,8 @@ impl VecMemory { use std::sync::Arc; +use crate::types::NamespaceSummary; use async_trait::async_trait; -use tinymemory_api::types::NamespaceSummary; #[async_trait] impl Memory for VecMemory { @@ -65,7 +65,7 @@ impl Memory for VecMemory { content, category, session_id, - tinymemory_api::types::MemoryTaint::Internal, + crate::types::MemoryTaint::Internal, ) .await } @@ -77,7 +77,7 @@ impl Memory for VecMemory { content: &str, category: MemoryCategory, session_id: Option<&str>, - taint: tinymemory_api::types::MemoryTaint, + taint: crate::types::MemoryTaint, ) -> anyhow::Result<()> { let entry = MemoryEntry { id: format!("{namespace}/{key}"), @@ -561,7 +561,7 @@ fn debug_renders_the_driver_id_and_not_the_backend() { assert!(!rendered.contains("VecMemory")); } -use tinymemory_api::capabilities::Capability; -use tinymemory_api::health::MemoryHealth; -use tinymemory_api::provider::{MemoryCore, MemoryPortability, MemoryProvider, MemoryRecall}; -use tinymemory_api::types::MemoryTaint; +use crate::capabilities::Capability; +use crate::health::MemoryHealth; +use crate::provider::{MemoryCore, MemoryPortability, MemoryProvider, MemoryRecall}; +use crate::types::MemoryTaint; diff --git a/core/Cargo.toml b/core/Cargo.toml index d876807..568363f 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -21,7 +21,6 @@ tinymemory-api = { path = "../api" } # different engine could not have Composio sync despite none of this code # caring which engine is bound. tinymemory-sync = { path = "../sync" } -tinymemory = { path = ".." } # The default embedded engine. `store/`, `tree/` and `sync/` drive it directly; # `tinycortex-api` is a direct dependency because `tinycortex::memory` aliases diff --git a/src/lib.rs b/src/lib.rs index 646626a..1b829b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,7 +63,31 @@ //! let capabilities = provider.capabilities(); //! ``` -pub mod mandatory; +/// The mandatory-family composition, re-exported from the contract crate. +/// +/// The module itself moved to `tinymemory-api` so the adapters can reach it +/// without depending on this crate — which is what lets this crate depend on +/// *them* and declare the per-engine features (#18 §D1). Re-exported rather +/// than relocated silently: `tinymemory::mandatory::MemoryTraitProvider` is a +/// path downstream code already uses. +pub use tinymemory_api::mandatory; + +/// The bundled TinyCortex embedded engine, when the `tinycortex` feature is on. +/// +/// Re-exported so a host selects an engine by feature rather than by taking a +/// second dependency: `tinymemory = { features = ["tinycortex"] }` is the whole +/// wiring, and `tinymemory::tinycortex::provider(backend)` binds it (#18 §D1). +#[cfg(feature = "tinycortex")] +pub use tinymemory_tinycortex as tinycortex; + +/// The hosted HTTP engines, when any of `supermemory`, `mem0` or `cognee` is on. +/// +/// One module for all three because they share one adapter crate — enabling +/// two of them costs one dependency, not two. The per-engine features still +/// exist so a host states which it actually uses, and so a future split can +/// happen without changing how hosts ask for them. +#[cfg(any(feature = "supermemory", feature = "mem0", feature = "cognee"))] +pub use tinymemory_remote as remote; pub mod registry; // The contract, re-exported wholesale. Listed module by module rather than as a diff --git a/src/registry/mod.rs b/src/registry/mod.rs index b5de045..f77425f 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -54,21 +54,17 @@ mod test; /// contract so hosts and adapters agree on the spelling. pub use tinymemory_api::null::NULL_DRIVER_ID; -/// The driver id of the bundled TinyCortex embedded engine. +/// The reserved driver ids, re-exported from the contract crate. /// -/// Lives here rather than in the adapter crate so admission can reserve the id -/// without depending on the adapter — a host that compiles the adapter out must -/// still refuse to bind something *else* under this name. -pub const TINYCORTEX_DRIVER_ID: &str = "tinycortex"; - -/// Driver id of the native Supermemory HTTP adapter. -pub const SUPERMEMORY_DRIVER_ID: &str = "supermemory"; - -/// Driver id of the native Mem0 HTTP adapter. -pub const MEM0_DRIVER_ID: &str = "mem0"; - -/// Driver id of the native Cognee HTTP adapter. -pub const COGNEE_DRIVER_ID: &str = "cognee"; +/// They moved to [`tinymemory_api::drivers`] so an adapter can spell the id it +/// binds under without depending on this crate — that dependency is what made +/// this crate unable to depend on the adapters in turn, and so blocked #18 +/// §D1's per-engine features. Re-exported here because +/// `tinymemory::registry::TINYCORTEX_DRIVER_ID` is a path both the adapters and +/// downstream hosts already use. +pub use tinymemory_api::drivers::{ + COGNEE_DRIVER_ID, MEM0_DRIVER_ID, SUPERMEMORY_DRIVER_ID, TINYCORTEX_DRIVER_ID, +}; /// The trust state a driver entry must carry for an external class to bind. pub const TRUSTED: &str = "trusted"; From 32cebbbd4c61615b06c7bb2484384e1e758cbe23 Mon Sep 17 00:00:00 2001 From: Shanu Date: Tue, 18 Aug 2026 18:28:22 +0530 Subject: [PATCH 2/2] =?UTF-8?q?Allow=20the=20CA-bundle=20data=20licence=20?= =?UTF-8?q?that=20=C2=A7D1=20pulls=20into=20the=20graph?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `Supply chain` failed: cargo-deny rejected `webpki-roots` for `CDLA-Permissive-2.0`. Advisories, bans and sources all pass; this was licences alone. It is a real consequence of this PR rather than a flake. `deny.toml` sets `[graph] all-features = true`, and before this branch the facade had no features to enable, so nothing on it pulled the remote adapter's TLS stack. Giving the facade `supermemory`/`mem0`/`cognee` puts `reqwest`-with-rustls, and so Mozilla's CA bundle, into the evaluated graph. `main` passes for exactly that reason, not because the crate was absent from its tree. Allowed rather than avoided, because the alternative is dropping HTTPS from the hosted engines. The licence is a *data* licence, which is why it was not already on a list of code licences: `webpki-roots` is Mozilla's trust store rendered as a Rust array, not software. CDLA-Permissive-2.0 places no conditions on use or redistribution of that data and adds no obligations to binaries that embed it. The entry carries that reasoning inline so the next person does not have to re-derive it. cargo deny check: advisories ok, bans ok, licences ok, sources ok --- deny.toml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/deny.toml b/deny.toml index 049b6f9..0aa3ac0 100644 --- a/deny.toml +++ b/deny.toml @@ -18,6 +18,20 @@ allow = [ "Apache-2.0 WITH LLVM-exception", "BSD-2-Clause", "BSD-3-Clause", + # `webpki-roots` — Mozilla's CA root bundle, reached through + # `reqwest`'s rustls-tls, which the hosted-engine adapter needs for HTTPS. + # + # A *data* licence rather than a code one, which is why it is not on the + # usual list: the crate is Mozilla's trust store rendered as a Rust array, + # not software. CDLA-Permissive-2.0 places no conditions on use or + # redistribution of that data and adds no obligations to the binaries that + # embed it. + # + # It reached this graph when #18 §D1 gave the facade per-engine features: + # `[graph] all-features = true` above now enables `supermemory`/`mem0`/ + # `cognee`, so the remote adapter's TLS stack is evaluated where before + # nothing on the facade pulled it. + "CDLA-Permissive-2.0", "GPL-3.0-only", "ISC", "MIT",