Skip to main content

crewai-endee

Endee vector database integration for CrewAI agent memory

crewai-endee connects Endee to CrewAI, giving your agents persistent memory with dense, hybrid, and multi-field retrieval.

Uses the same fields= configuration as the Endee Python client's create_collection().


Installation

Requires Python 3.10–3.13.

pip install crewai-endee

This installs endee, endee_model, and crewai automatically.


Quick Start

from crewai_endee import EndeeVectorStore

store = EndeeVectorStore(
    type="my_collection",
    embedder_config={
        "provider": "sentence-transformer",
        "config": {"model_name": "all-MiniLM-L6-v2"},
    },
    fields=[
        {"name": "dense", "type": "vector",
         "params": {"dimension": 384, "space_type": "cosine", "precision": "int8"}},
    ],
)

store.save("Go is a statically typed language by Google.", {"lang": "Go"})
results = store.search("static typing", limit=3)

Connect to Endee

With API token

Sign up at endee.io and get your token. See the Endee docs for details.

store = EndeeVectorStore(
    type="my_collection",
    embedder_config=embedder_config,
    api_token="YOUR_ENDEE_API_TOKEN",
    fields=[
        {"name": "dense", "type": "vector",
         "params": {"dimension": 384, "space_type": "cosine", "precision": "int8"}},
    ],
)

Without API token (local)

Run the open-source Endee server locally. See github.com/endee-io/endee for setup. Omit api_token:

store = EndeeVectorStore(
    type="my_collection",
    embedder_config=embedder_config,
    fields=[
        {"name": "dense", "type": "vector",
         "params": {"dimension": 384, "space_type": "cosine", "precision": "int8"}},
    ],
)

Dense Mode

from crewai_endee import EndeeVectorStore

store = EndeeVectorStore(
    type="demo_dense",
    embedder_config=embedder_config,
    fields=[
        {"name": "dense", "type": "vector",
         "params": {"dimension": 384, "space_type": "cosine", "precision": "int8"}},
    ],
    force_recreate=True,
)

store.save("Python is a dynamic language.", {"lang": "Python"})
results = store.search("dynamic typing", limit=3)

Hybrid Mode (endee_bm25 — auto-encoded)

Add a sparse field with "sparse_model": "endee_bm25". The BM25 sparse encoder is created automatically — no extra setup needed:

store = EndeeVectorStore(
    type="demo_hybrid",
    embedder_config=embedder_config,
    fields=[
        {"name": "dense", "type": "vector",
         "params": {"dimension": 384, "space_type": "cosine", "precision": "int8"}},
        {"name": "sparse", "type": "sparse",
         "sparse_model": "endee_bm25"},
    ],
    force_recreate=True,
)

store.save("Go has native concurrency.", {"lang": "Go"})

# Hybrid search — dense similarity + BM25 keyword matching, fused via RRF
results = store.search("concurrency", limit=3)

# Tune fusion weights
results = store.search(
    "concurrency", limit=3,
    field_weights={"dense": 0.3, "sparse": 0.7},
    rrf_k=30,
)

Hybrid Mode (default sparse — user-provided vectors)

Use "sparse_model": "default" and provide your own sparse vectors via add_objects() and multi_field_search():

import uuid
from endee import rerank

store = EndeeVectorStore(
    type="demo_hybrid_default",
    embedder_config=embedder_config,
    fields=[
        {"name": "dense", "type": "vector",
         "params": {"dimension": 384, "space_type": "cosine", "precision": "int8"}},
        {"name": "sparse", "type": "sparse", "sparse_model": "default"},
    ],
    force_recreate=True,
)

# Upsert with user-provided sparse vectors
store.add_objects([{
    "id": uuid.uuid4().hex,
    "meta": {"text": "Python ML libraries", "metadata": {"lang": "Python"}},
    "filter": {"lang": "Python"},
    "fields": {
        "dense": store.embedder(["Python ML libraries"])[0].tolist(),
        "sparse": {"indices": [10, 42, 99], "values": [0.9, 0.4, 0.7]},
    },
}])

# Search both fields with user-provided sparse query
raw = store.multi_field_search(fields={
    "dense":  {"query": store.embedder(["ML"])[0].tolist(), "limit": 3},
    "sparse": {"query": {"indices": [10, 42], "values": [0.8, 0.5]}, "limit": 3},
})
fused = rerank(raw, limit=3, field_weights={"dense": 0.5, "sparse": 0.5})

Multi-Vector Mode

Add a multi_vector field for per-chunk or ColBERT-style embeddings:

store = EndeeVectorStore(
    type="demo_multi_vector",
    embedder_config=embedder_config,
    fields=[
        {"name": "dense", "type": "vector",
         "params": {"dimension": 384, "space_type": "cosine", "precision": "int8"}},
        {"name": "chunks", "type": "multi_vector",
         "params": {"dimension": 384, "space_type": "cosine",
                    "precision": "int8", "pooling": "mean"}},
    ],
    force_recreate=True,
)

# Upsert with multi-vector data via add_objects
store.add_objects([{
    "id": uuid.uuid4().hex,
    "meta": {"text": "Long article about distributed systems.", "metadata": {}},
    "filter": {},
    "fields": {
        "dense": store.embedder(["Long article about distributed systems."])[0].tolist(),
        "chunks": [[0.1, ...], [0.3, ...], [0.5, ...]],  # pre-computed chunk embeddings
    },
}])

# Dense-only search still works
results = store.search("distributed systems", limit=3)

# Multi-field search with rerank
raw = store.multi_field_search(fields={
    "dense":  {"query": store.embedder(["consensus"])[0].tolist(), "limit": 3},
    "chunks": {"query": [[0.1, ...], [0.3, ...]], "limit": 3},
})
fused = rerank(raw, limit=3, field_weights={"dense": 0.6, "chunks": 0.4})

Search with Filters

Endee uses MongoDB-style operator syntax:

# Filter by exact match
results = store.search("web language", limit=3, filter=[{"lang": {"$eq": "Python"}}])

# Filter with score threshold
results = store.search("systems", limit=3, score_threshold=0.3)

# Include raw vectors in results
results = store.search("Python", limit=1, include_vectors=True)

# HNSW tuning
results = store.search("query", limit=3, ef_search=256)

# Filtered search tuning
results = store.search(
    "query", limit=3,
    filter=[{"category": {"$eq": "systems"}}],
    prefilter_cardinality_threshold=5000,
    filter_boost_percentage=50,
)

Supported operators: $eq, $ne, $gt, $gte, $lt, $lte, $in


Collection Operations

# Describe collection metadata
info = store.describe()

# Retrieve objects by ID
objects = store.get_objects(["id1", "id2"])

# Retrieve a single object by ID
obj = store.get_vector("some_id")

# Update filter metadata without re-embedding
store.update_filters([{"id": "some_id", "filter": {"reviewed": "true"}}])

# Delete a single object by ID
store.delete_vector("some_id")

# Delete all objects matching a filter
store.delete(filter=[{"category": {"$eq": "outdated"}}])

# Delete the entire collection
store.reset()

# Close the connection
store.close()

CrewAI Integration

EndeeVectorStore extends CrewAI's BaseRAGStorage. Wire it into a Crew via ShortTermMemory and EntityMemory:

from crewai import LLM, Agent, Crew, Process, Task
from crewai.memory.short_term.short_term_memory import ShortTermMemory
from crewai.memory.entity.entity_memory import EntityMemory
from crewai_endee import EndeeVectorStore

embedder_config = {
    "provider": "sentence-transformer",
    "config": {"model_name": "all-MiniLM-L6-v2"},
}

fields = [
    {"name": "dense", "type": "vector",
     "params": {"dimension": 384, "space_type": "cosine", "precision": "int8"}},
]

stm_store = EndeeVectorStore(
    type="crew_short_term",
    embedder_config=embedder_config,
    fields=fields,
)

entity_store = EndeeVectorStore(
    type="crew_entity",
    embedder_config=embedder_config,
    fields=fields,
)

short_term_memory = ShortTermMemory(storage=stm_store)
entity_memory = EntityMemory(storage=entity_store)

llm = LLM(model="gemini/gemini-2.5-flash", api_key=GOOGLE_API_KEY)

agent = Agent(
    role="Software Analyst",
    goal="Extract programming language characteristics",
    backstory="You study programming language design.",
    llm=llm,
)

task = Task(
    description="Analyse key characteristics of Python, Java, and Go.",
    expected_output="Structured summary of each language.",
    agent=agent,
)

crew = Crew(
    agents=[agent],
    tasks=[task],
    process=Process.sequential,
    memory=True,
    short_term_memory=short_term_memory,
    entity_memory=entity_memory,
    embedder=embedder_config,
    verbose=True,
)

result = crew.kickoff()

API Reference

Constructor

EndeeVectorStore(
    type: str,                          # Collection name (required)
    embedder_config: dict,              # Dense embedder config (required)
    fields: list[dict],                 # Field definitions (required)
    api_token: str = None,              # Endee API token
    base_url: str = None,               # Custom API URL
    endee_client: EndeeClient = None,   # Pre-existing client
    sparse_embedding: SparseEmbeddings = None,  # Custom sparse model
    content_payload_key: str = "text",
    metadata_payload_key: str = "metadata",
    force_recreate: bool = False,       # Delete and recreate if exists
)

Field Types

# Dense vector
{"name": "dense", "type": "vector",
 "params": {"dimension": 384, "space_type": "cosine",
            "precision": "int8", "M": 16, "ef_con": 128}}

# Sparse (endee_bm25 — auto-encoded)
{"name": "sparse", "type": "sparse", "sparse_model": "endee_bm25"}

# Sparse (default — user provides vectors)
{"name": "sparse", "type": "sparse", "sparse_model": "default"}

# Multi-vector
{"name": "chunks", "type": "multi_vector",
 "params": {"dimension": 128, "space_type": "cosine",
            "precision": "float16", "pooling": "mean"}}

Methods

Method Description
save(value, metadata) Embed text and upsert (dense + auto sparse)
search(query, limit, filter, ...) Search with optional filters and RRF fusion
add_objects(objects) Upsert arbitrary per-field data
multi_field_search(fields, filter) Search multiple fields, raw per-field results
ensure_collection() Verify collection exists
describe() Collection metadata
get_objects(ids) Retrieve objects by ID list
get_vector(id) Retrieve single object by ID
update_filters(updates) Update filter metadata without re-embedding
delete_vector(id) Delete single object by ID
delete(filter) Delete by metadata filter
reset() Delete entire collection
close() Close HTTP connection

Search Parameters

Parameter Default Description
query (required) Natural-language search query
limit 3 Max results
filter None [{"field": {"$op": value}}]
score_threshold 0 Minimum similarity score
ef_search None HNSW ef (default 128, max 1024)
include_vectors False Fetch raw vector data
field_weights None Per-field RRF weights (sum to 1.0)
rrf_k 60 RRF rank constant
prefilter_cardinality_threshold None Brute-force pre-filter threshold
filter_boost_percentage None Candidate pool expansion (0-100)

Exports

from crewai_endee import (
    EndeeVectorStore,
    EndeeModelSparse,
    SparseEmbeddings,
    SparseVector,
    Precision,
    rerank,
)

Full Endee documentation: docs.endee.io | GitHub: endee-io/endee | CrewAI docs: docs.crewai.com

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

crewai_endee-1.1.0.tar.gz (16.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

crewai_endee-1.1.0-py3-none-any.whl (13.2 kB view details)

Uploaded Python 3

File details

Details for the file crewai_endee-1.1.0.tar.gz.

File metadata

  • Download URL: crewai_endee-1.1.0.tar.gz
  • Upload date:
  • Size: 16.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for crewai_endee-1.1.0.tar.gz
Algorithm Hash digest
SHA256 10799ad5acac08f54c475313f0c1f3bfc092122f60cd056780e1fcf2c63966a8
MD5 5727d02a271d8c17f57fd5aa5f2d43f1
BLAKE2b-256 ed083195047eea5f089b494934059e6e4eb6562c549c6935b537f03d195b5fbf

See more details on using hashes here.

File details

Details for the file crewai_endee-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: crewai_endee-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for crewai_endee-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2f70df93079e40103cf4cc2634e4a22544033e9a375fdc6480cb87d7e3eb3d7e
MD5 dd1aa3274a899ebd123d3f2d623a18fe
BLAKE2b-256 b05b2bb7f5fcbef3c302b3ba4ce9d93c7dd57cdef43c529c74cf20ad88098327

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 files

0.1.2

2 files

0.1.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page