LangChain / ChromaDB adapter
| This documentation is for an as-yet unreleased version of Cerbos. Choose 0.50.0 from the version picker at the top right or navigate to https://docs.cerbos.dev for the latest version. |
The @cerbos/langchain-chromadb package converts a Cerbos PlanResources response into a ChromaDB Where filter object compatible with the LangChain.js Chroma vector store. This enables authorization-aware similarity searches where Cerbos policy conditions are pushed down as metadata filters.
Supported operators
| Category | Operators |
|---|---|
Logical |
|
Negation |
|
Comparison |
|
Membership |
|
Negation handling
ChromaDB has no $not or $nor filter. The adapter handles not expressions by inverting the inner operator:
-
not(eq)becomes$ne;not(ne)becomes$eq -
not(lt)becomes$gte;not(gt)becomes$lte;not(le)becomes$gt;not(ge)becomes$lt -
not(in)becomes$nin -
not(and(A, B))becomes$or[not(A), not(B)](De Morgan’s law) -
not(or(A, B))becomes$and[not(A), not(B)](De Morgan’s law) -
not(not(X))becomesX(double negation elimination)
Usage
import { queryPlanToChromaDB, PlanKind } from "@cerbos/langchain-chromadb";
import { Chroma } from "@langchain/community/vectorstores/chroma";
import { OpenAIEmbeddings } from "@langchain/openai";
const queryPlan = await cerbos.planResources({
principal: { id: "user1", roles: ["USER"] },
resource: { kind: "document" },
action: "view",
});
const result = queryPlanToChromaDB({
queryPlan,
fieldNameMapper: {
"request.resource.attr.department": "department",
"request.resource.attr.public": "public",
},
});
if (result.kind === PlanKind.ALWAYS_DENIED) {
return [];
}
const chroma = await Chroma.fromExistingCollection(
new OpenAIEmbeddings(),
{ collectionName: "my_collection" },
);
const filters =
result.kind === PlanKind.CONDITIONAL ? result.filters : undefined;
const matches = await chroma.similaritySearch("query", 10, filters);
Field name mapper
The mapper translates Cerbos attribute references to ChromaDB metadata field names. It accepts an object or a function.
// Object mapper
const result = queryPlanToChromaDB({
queryPlan,
fieldNameMapper: {
"request.resource.attr.aBool": "aBool",
"request.resource.attr.aString": "title",
},
});
// Function mapper
const result = queryPlanToChromaDB({
queryPlan,
fieldNameMapper: (fieldName) =>
fieldName.replace("request.resource.attr.", ""),
});
If a field is not found in the object mapper, the original Cerbos path is used as-is.