diff --git a/api/src/null.rs b/api/src/null.rs index 482bc5c..df2bc69 100644 --- a/api/src/null.rs +++ b/api/src/null.rs @@ -235,6 +235,29 @@ impl MemoryDocuments for NullMemoryProvider { unsupported(Capability::Documents) } + async fn list_documents( + &self, + _namespace: Option<&str>, + ) -> Result { + unsupported(Capability::Documents) + } + + async fn list_namespaces(&self) -> Result, MemoryError> { + unsupported(Capability::Documents) + } + + async fn delete_document( + &self, + _namespace: &str, + _document_id: &str, + ) -> Result { + unsupported(Capability::Documents) + } + + async fn clear_namespace(&self, _namespace: &str) -> Result<(), MemoryError> { + unsupported(Capability::Documents) + } + async fn query_documents( &self, _namespace: &str, @@ -326,6 +349,10 @@ impl MemoryGraph for NullMemoryProvider { unsupported(Capability::Graph) } + async fn kv_delete(&self, _namespace: Option<&str>, _key: &str) -> Result { + unsupported(Capability::Graph) + } + async fn kv_list( &self, _namespace: Option<&str>, diff --git a/api/src/provider/content.rs b/api/src/provider/content.rs index 9c16e86..cde5867 100644 --- a/api/src/provider/content.rs +++ b/api/src/provider/content.rs @@ -85,6 +85,42 @@ pub trait MemoryDocuments: Send + Sync { key: &str, ) -> Result, MemoryError>; + /// List document summaries, optionally restricted to one namespace. + /// + /// # Errors + /// + /// Backend failures only. + async fn list_documents( + &self, + namespace: Option<&str>, + ) -> Result; + + /// List every namespace containing documents. + /// + /// # Errors + /// + /// Backend failures only. + async fn list_namespaces(&self) -> Result, MemoryError>; + + /// Delete a document by its driver-assigned id. + /// + /// # Errors + /// + /// Backend failures only; a missing document is reported in the returned + /// outcome rather than as an error. + async fn delete_document( + &self, + namespace: &str, + document_id: &str, + ) -> Result; + + /// Delete all data belonging to one namespace. + /// + /// # Errors + /// + /// Backend failures only. + async fn clear_namespace(&self, namespace: &str) -> Result<(), MemoryError>; + /// Run a ranked query over one namespace's documents. /// /// Returns both the ranked hits and the driver's rendered context text, so diff --git a/api/src/provider/knowledge.rs b/api/src/provider/knowledge.rs index 45140e5..a1ae366 100644 --- a/api/src/provider/knowledge.rs +++ b/api/src/provider/knowledge.rs @@ -97,6 +97,13 @@ pub trait MemoryGraph: Send + Sync { value: serde_json::Value, ) -> Result<(), MemoryError>; + /// Delete one key/value record, reporting whether it existed. + /// + /// # Errors + /// + /// Backend failures only. + async fn kv_delete(&self, namespace: Option<&str>, key: &str) -> Result; + /// List key/value records, optionally restricted to a key prefix. /// /// # Errors diff --git a/api/src/version.rs b/api/src/version.rs index 9724674..7d68fd0 100644 --- a/api/src/version.rs +++ b/api/src/version.rs @@ -60,7 +60,7 @@ /// added to a family a driver may already advertise** (negotiation is /// family-granular, not method-granular, so that case cannot be made minor-safe /// by negotiation alone). -pub const CONTRACT_VERSION: (u16, u16) = (1, 0); +pub const CONTRACT_VERSION: (u16, u16) = (2, 0); /// Whether a driver speaking `remote` can be bound against this build. /// diff --git a/api/src/version_tests.rs b/api/src/version_tests.rs index 1b3a4c0..b6baf39 100644 --- a/api/src/version_tests.rs +++ b/api/src/version_tests.rs @@ -8,7 +8,7 @@ use super::*; #[test] fn contract_version_starts_at_one_zero() { - assert_eq!(CONTRACT_VERSION, (1, 0)); + assert_eq!(CONTRACT_VERSION, (2, 0)); } #[test] diff --git a/crates/tinymemory-module/src/lib.rs b/crates/tinymemory-module/src/lib.rs index 9a9e2cd..9d48288 100644 --- a/crates/tinymemory-module/src/lib.rs +++ b/crates/tinymemory-module/src/lib.rs @@ -228,6 +228,10 @@ mod exports { "IngestChat", "PutDocument", "GetDocument", + "ListDocuments", + "ListNamespaces", + "DeleteDocument", + "ClearNamespace", "QueryDocuments", "Append", "QuerySource", @@ -239,6 +243,7 @@ mod exports { "TouchEntities", "KvGet", "KvPut", + "KvDelete", "KvList", "Relations", "PutRelation", diff --git a/crates/tinymemory-module/src/provider.rs b/crates/tinymemory-module/src/provider.rs index 357ee61..123a097 100644 --- a/crates/tinymemory-module/src/provider.rs +++ b/crates/tinymemory-module/src/provider.rs @@ -343,6 +343,41 @@ impl MemoryDocuments for ModuleMemoryProvider { .map(|document| Self::cross(&document, "convert stored document")) .transpose() } + + async fn list_documents( + &self, + namespace: Option<&str>, + ) -> Result { + self.client + .list_documents(namespace) + .await + .map_err(|error| Self::other("list_documents", error)) + } + + async fn list_namespaces(&self) -> Result, MemoryError> { + self.client + .list_namespaces() + .await + .map_err(|error| Self::other("list_namespaces", error)) + } + + async fn delete_document( + &self, + namespace: &str, + document_id: &str, + ) -> Result { + self.client + .delete_document(namespace, document_id) + .await + .map_err(|error| Self::other("delete_document", error)) + } + + async fn clear_namespace(&self, namespace: &str) -> Result<(), MemoryError> { + self.client + .clear_namespace(namespace) + .await + .map_err(|error| Self::other("clear_namespace", error)) + } async fn query_documents( &self, namespace: &str, @@ -472,6 +507,13 @@ impl MemoryGraph for ModuleMemoryProvider { .await .map_err(|error| Self::other("kv_put", error)) } + + async fn kv_delete(&self, namespace: Option<&str>, key: &str) -> Result { + self.client + .kv_delete(namespace, key) + .await + .map_err(|error| Self::other("kv_delete", error)) + } async fn kv_list( &self, namespace: Option<&str>, diff --git a/crates/tinymemory-module/src/service/mod.rs b/crates/tinymemory-module/src/service/mod.rs index d7877de..f39800f 100644 --- a/crates/tinymemory-module/src/service/mod.rs +++ b/crates/tinymemory-module/src/service/mod.rs @@ -313,6 +313,38 @@ impl MemoryService { .map_err(|error| into_bus_error(&error)) } + async fn list_documents(&self, namespace: Option) -> BusResult { + require_family!(self, as_documents, Capability::Documents) + .list_documents(namespace.as_deref()) + .await + .map_err(|error| into_bus_error(&error)) + } + + async fn list_namespaces(&self) -> BusResult> { + require_family!(self, as_documents, Capability::Documents) + .list_namespaces() + .await + .map_err(|error| into_bus_error(&error)) + } + + async fn delete_document( + &self, + namespace: String, + document_id: String, + ) -> BusResult { + require_family!(self, as_documents, Capability::Documents) + .delete_document(&namespace, &document_id) + .await + .map_err(|error| into_bus_error(&error)) + } + + async fn clear_namespace(&self, namespace: String) -> BusResult<()> { + require_family!(self, as_documents, Capability::Documents) + .clear_namespace(&namespace) + .await + .map_err(|error| into_bus_error(&error)) + } + async fn query_documents( &self, namespace: String, @@ -426,6 +458,13 @@ impl MemoryService { .map_err(|error| into_bus_error(&error)) } + async fn kv_delete(&self, namespace: Option, key: String) -> BusResult { + require_family!(self, as_graph, Capability::Graph) + .kv_delete(namespace.as_deref(), &key) + .await + .map_err(|error| into_bus_error(&error)) + } + async fn kv_list( &self, namespace: Option, diff --git a/crates/tinymemory-module/tests/module_e2e.rs b/crates/tinymemory-module/tests/module_e2e.rs index 7e2ea9c..3115081 100644 --- a/crates/tinymemory-module/tests/module_e2e.rs +++ b/crates/tinymemory-module/tests/module_e2e.rs @@ -496,6 +496,10 @@ const EXPECTED_METHODS: &[&str] = &[ "IngestChat", "PutDocument", "GetDocument", + "ListDocuments", + "ListNamespaces", + "DeleteDocument", + "ClearNamespace", "QueryDocuments", "Append", "QuerySource", @@ -507,6 +511,7 @@ const EXPECTED_METHODS: &[&str] = &[ "TouchEntities", "KvGet", "KvPut", + "KvDelete", "KvList", "Relations", "PutRelation",