Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

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.0b0.tar.gz (16.6 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.0b0-py3-none-any.whl (13.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: crewai_endee-1.1.0b0.tar.gz
  • Upload date:
  • Size: 16.6 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.0b0.tar.gz
Algorithm Hash digest
SHA256 35182f23e104159a91bf7d3d8b1ea0c8db935f5c5c0bac8660b17ef0eae8a2cb
MD5 a54fbe1e6f6547eae6c954be28ef225b
BLAKE2b-256 543241e4f9a1bfe934449ff9ef62aeda3fdd65347f37d1e8811f133eec3800f4

See more details on using hashes here.

File details

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

File metadata

  • Download URL: crewai_endee-1.1.0b0-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.0b0-py3-none-any.whl
Algorithm Hash digest
SHA256 c477c6e94c9046df6f5e73e69c05ee2bd0cfe0240f32b968535488e5b3530a2a
MD5 6b534f52496ac2ba3c84448bdd680500
BLAKE2b-256 f21eb36c3f4eb04a955880929b6b10ae7f25023ad60d1288d7c6edaba182f50a

See more details on using hashes here.

Release history Release notifications | RSS feed

1.1.0

2 files

This release

1.1.0b0 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