@@ -154,11 +154,18 @@ def __init__(
154154 # Embedding provider
155155 self ._embedder = embedder
156156
157- # Audit provider
157+ # Audit provider (auto-detect qp-capsule if installed)
158158 if auditor is not None :
159159 self ._auditor = auditor
160160 else :
161- self ._auditor = LogAuditor (self .path / "audit.jsonl" )
161+ try :
162+ from qp_vault .audit .capsule_auditor import HAS_CAPSULE , CapsuleAuditor
163+ if HAS_CAPSULE :
164+ self ._auditor = CapsuleAuditor ()
165+ else :
166+ self ._auditor = LogAuditor (self .path / "audit.jsonl" )
167+ except ImportError :
168+ self ._auditor = LogAuditor (self .path / "audit.jsonl" )
162169
163170 # Parsers and policies
164171 self ._parsers = parsers or []
@@ -213,6 +220,7 @@ async def add(
213220 lifecycle : Lifecycle | str = Lifecycle .ACTIVE ,
214221 valid_from : date | None = None ,
215222 valid_until : date | None = None ,
223+ tenant_id : str | None = None ,
216224 ) -> Resource :
217225 """Add a resource to the vault.
218226
@@ -325,6 +333,7 @@ async def add(
325333 lifecycle = lifecycle ,
326334 valid_from = valid_from ,
327335 valid_until = valid_until ,
336+ tenant_id = tenant_id ,
328337 )
329338
330339 async def get (self , resource_id : str ) -> Resource :
@@ -335,6 +344,7 @@ async def get(self, resource_id: str) -> Resource:
335344 async def list (
336345 self ,
337346 * ,
347+ tenant_id : str | None = None ,
338348 trust : TrustTier | str | None = None ,
339349 classification : DataClassification | str | None = None ,
340350 layer : MemoryLayer | str | None = None ,
@@ -348,6 +358,7 @@ async def list(
348358 """List resources with optional filters."""
349359 await self ._ensure_initialized ()
350360 return await self ._resource_manager .list (
361+ tenant_id = tenant_id ,
351362 trust = trust ,
352363 classification = classification ,
353364 layer = layer ,
@@ -511,6 +522,7 @@ async def search(
511522 self ,
512523 query : str ,
513524 * ,
525+ tenant_id : str | None = None ,
514526 top_k : int = 10 ,
515527 threshold : float = 0.0 ,
516528 trust_min : TrustTier | str | None = None ,
@@ -551,10 +563,11 @@ async def search(
551563 vector_weight = self .config .vector_weight ,
552564 text_weight = self .config .text_weight ,
553565 filters = ResourceFilter (
566+ tenant_id = tenant_id ,
554567 trust_tier = trust_min .value if hasattr (trust_min , "value" ) else trust_min ,
555568 layer = layer .value if hasattr (layer , "value" ) else layer ,
556569 collection_id = collection ,
557- ) if any ([trust_min , layer , collection ]) else None ,
570+ ) if any ([tenant_id , trust_min , layer , collection ]) else None ,
558571 as_of = str (as_of ) if as_of else None ,
559572 )
560573
@@ -692,6 +705,36 @@ def layer(self, name: MemoryLayer | str) -> LayerView:
692705 layer_enum = MemoryLayer (name ) if isinstance (name , str ) else name
693706 return LayerView (layer_enum , self , self ._layer_manager )
694707
708+ # --- Collections ---
709+
710+ async def create_collection (
711+ self ,
712+ name : str ,
713+ * ,
714+ description : str = "" ,
715+ tenant_id : str | None = None ,
716+ ) -> dict [str , Any ]:
717+ """Create a new collection."""
718+ await self ._ensure_initialized ()
719+ import uuid
720+ from datetime import UTC , datetime
721+ collection_id = str (uuid .uuid4 ())
722+ now = datetime .now (tz = UTC ).isoformat ()
723+ conn = self ._storage ._get_conn () # type: ignore[union-attr]
724+ conn .execute (
725+ "INSERT INTO collections (id, name, description, created_at, updated_at) VALUES (?, ?, ?, ?, ?)" ,
726+ (collection_id , name , description , now , now ),
727+ )
728+ conn .commit ()
729+ return {"id" : collection_id , "name" : name , "description" : description }
730+
731+ async def list_collections (self , * , tenant_id : str | None = None ) -> list [dict [str , Any ]]:
732+ """List all collections."""
733+ await self ._ensure_initialized ()
734+ conn = self ._storage ._get_conn () # type: ignore[union-attr]
735+ rows = conn .execute ("SELECT * FROM collections ORDER BY name" ).fetchall ()
736+ return [dict (r ) for r in rows ]
737+
695738 # --- Integrity ---
696739
697740 async def health (self ) -> HealthScore :
@@ -885,6 +928,16 @@ def layer(self, name: MemoryLayer | str) -> LayerView: # type: ignore[return-va
885928 """Get a scoped view of a memory layer."""
886929 return self ._async .layer (name ) # type: ignore[return-value]
887930
931+ def create_collection (self , name : str , ** kwargs : Any ) -> dict [str , Any ]:
932+ """Create a new collection."""
933+ result : dict [str , Any ] = _run_async (self ._async .create_collection (name , ** kwargs ))
934+ return result
935+
936+ def list_collections (self , ** kwargs : Any ) -> list [dict [str , Any ]]:
937+ """List all collections."""
938+ result : list [dict [str , Any ]] = _run_async (self ._async .list_collections (** kwargs ))
939+ return result
940+
888941 def health (self ) -> HealthScore :
889942 """Compute vault health score."""
890943 result : HealthScore = _run_async (self ._async .health ())
0 commit comments