agno 2.0.1__py3-none-any.whl → 2.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agno/agent/agent.py +6015 -2823
- agno/api/api.py +2 -0
- agno/api/os.py +1 -1
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +385 -6
- agno/db/dynamo/dynamo.py +388 -81
- agno/db/dynamo/schemas.py +47 -10
- agno/db/dynamo/utils.py +63 -4
- agno/db/firestore/firestore.py +435 -64
- agno/db/firestore/schemas.py +11 -0
- agno/db/firestore/utils.py +102 -4
- agno/db/gcs_json/gcs_json_db.py +384 -42
- agno/db/gcs_json/utils.py +60 -26
- agno/db/in_memory/in_memory_db.py +351 -66
- agno/db/in_memory/utils.py +60 -2
- agno/db/json/json_db.py +339 -48
- agno/db/json/utils.py +60 -26
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +510 -37
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +15 -1
- agno/db/mongo/async_mongo.py +2036 -0
- agno/db/mongo/mongo.py +653 -76
- agno/db/mongo/schemas.py +13 -0
- agno/db/mongo/utils.py +80 -8
- agno/db/mysql/mysql.py +687 -25
- agno/db/mysql/schemas.py +61 -37
- agno/db/mysql/utils.py +60 -2
- agno/db/postgres/__init__.py +2 -1
- agno/db/postgres/async_postgres.py +2001 -0
- agno/db/postgres/postgres.py +676 -57
- agno/db/postgres/schemas.py +43 -18
- agno/db/postgres/utils.py +164 -2
- agno/db/redis/redis.py +344 -38
- agno/db/redis/schemas.py +18 -0
- agno/db/redis/utils.py +60 -2
- agno/db/schemas/__init__.py +2 -1
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/memory.py +13 -0
- agno/db/singlestore/schemas.py +26 -1
- agno/db/singlestore/singlestore.py +687 -53
- agno/db/singlestore/utils.py +60 -2
- agno/db/sqlite/__init__.py +2 -1
- agno/db/sqlite/async_sqlite.py +2371 -0
- agno/db/sqlite/schemas.py +24 -0
- agno/db/sqlite/sqlite.py +774 -85
- agno/db/sqlite/utils.py +168 -5
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +309 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1361 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +50 -22
- agno/eval/accuracy.py +50 -43
- agno/eval/performance.py +6 -3
- agno/eval/reliability.py +6 -3
- agno/eval/utils.py +33 -16
- agno/exceptions.py +68 -1
- agno/filters.py +354 -0
- agno/guardrails/__init__.py +6 -0
- agno/guardrails/base.py +19 -0
- agno/guardrails/openai.py +144 -0
- agno/guardrails/pii.py +94 -0
- agno/guardrails/prompt_injection.py +52 -0
- agno/integrations/discord/client.py +1 -0
- agno/knowledge/chunking/agentic.py +13 -10
- agno/knowledge/chunking/fixed.py +1 -1
- agno/knowledge/chunking/semantic.py +40 -8
- agno/knowledge/chunking/strategy.py +59 -15
- agno/knowledge/embedder/aws_bedrock.py +9 -4
- agno/knowledge/embedder/azure_openai.py +54 -0
- agno/knowledge/embedder/base.py +2 -0
- agno/knowledge/embedder/cohere.py +184 -5
- agno/knowledge/embedder/fastembed.py +1 -1
- agno/knowledge/embedder/google.py +79 -1
- agno/knowledge/embedder/huggingface.py +9 -4
- agno/knowledge/embedder/jina.py +63 -0
- agno/knowledge/embedder/mistral.py +78 -11
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/ollama.py +13 -0
- agno/knowledge/embedder/openai.py +37 -65
- agno/knowledge/embedder/sentence_transformer.py +8 -4
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +69 -16
- agno/knowledge/knowledge.py +594 -186
- agno/knowledge/reader/base.py +9 -2
- agno/knowledge/reader/csv_reader.py +8 -10
- agno/knowledge/reader/docx_reader.py +5 -6
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/json_reader.py +6 -5
- agno/knowledge/reader/markdown_reader.py +13 -13
- agno/knowledge/reader/pdf_reader.py +43 -68
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +51 -6
- agno/knowledge/reader/s3_reader.py +3 -15
- agno/knowledge/reader/tavily_reader.py +194 -0
- agno/knowledge/reader/text_reader.py +13 -13
- agno/knowledge/reader/web_search_reader.py +2 -43
- agno/knowledge/reader/website_reader.py +43 -25
- agno/knowledge/reranker/__init__.py +2 -8
- agno/knowledge/types.py +9 -0
- agno/knowledge/utils.py +20 -0
- agno/media.py +72 -0
- agno/memory/manager.py +336 -82
- agno/models/aimlapi/aimlapi.py +2 -2
- agno/models/anthropic/claude.py +183 -37
- agno/models/aws/bedrock.py +52 -112
- agno/models/aws/claude.py +33 -1
- agno/models/azure/ai_foundry.py +33 -15
- agno/models/azure/openai_chat.py +25 -8
- agno/models/base.py +999 -519
- agno/models/cerebras/cerebras.py +19 -13
- agno/models/cerebras/cerebras_openai.py +8 -5
- agno/models/cohere/chat.py +27 -1
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +57 -0
- agno/models/dashscope/dashscope.py +1 -0
- agno/models/deepinfra/deepinfra.py +2 -2
- agno/models/deepseek/deepseek.py +2 -2
- agno/models/fireworks/fireworks.py +2 -2
- agno/models/google/gemini.py +103 -31
- agno/models/groq/groq.py +28 -11
- agno/models/huggingface/huggingface.py +2 -1
- agno/models/internlm/internlm.py +2 -2
- agno/models/langdb/langdb.py +4 -4
- agno/models/litellm/chat.py +18 -1
- agno/models/litellm/litellm_openai.py +2 -2
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/message.py +139 -0
- agno/models/meta/llama.py +27 -10
- agno/models/meta/llama_openai.py +5 -17
- agno/models/nebius/nebius.py +6 -6
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/nvidia.py +2 -2
- agno/models/ollama/chat.py +59 -5
- agno/models/openai/chat.py +69 -29
- agno/models/openai/responses.py +103 -106
- agno/models/openrouter/openrouter.py +41 -3
- agno/models/perplexity/perplexity.py +4 -5
- agno/models/portkey/portkey.py +3 -3
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +52 -0
- agno/models/response.py +77 -1
- agno/models/sambanova/sambanova.py +2 -2
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +25 -0
- agno/models/together/together.py +2 -2
- agno/models/utils.py +254 -8
- agno/models/vercel/v0.py +2 -2
- agno/models/vertexai/__init__.py +0 -0
- agno/models/vertexai/claude.py +96 -0
- agno/models/vllm/vllm.py +1 -0
- agno/models/xai/xai.py +3 -2
- agno/os/app.py +543 -178
- agno/os/auth.py +24 -14
- agno/os/config.py +1 -0
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/a2a/__init__.py +3 -0
- agno/os/interfaces/a2a/a2a.py +42 -0
- agno/os/interfaces/a2a/router.py +250 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/agui.py +23 -7
- agno/os/interfaces/agui/router.py +27 -3
- agno/os/interfaces/agui/utils.py +242 -142
- agno/os/interfaces/base.py +6 -2
- agno/os/interfaces/slack/router.py +81 -23
- agno/os/interfaces/slack/slack.py +29 -14
- agno/os/interfaces/whatsapp/router.py +11 -4
- agno/os/interfaces/whatsapp/whatsapp.py +14 -7
- agno/os/mcp.py +111 -54
- agno/os/middleware/__init__.py +7 -0
- agno/os/middleware/jwt.py +233 -0
- agno/os/router.py +556 -139
- agno/os/routers/evals/evals.py +71 -34
- agno/os/routers/evals/schemas.py +31 -31
- agno/os/routers/evals/utils.py +6 -5
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/knowledge.py +185 -38
- agno/os/routers/knowledge/schemas.py +82 -22
- agno/os/routers/memory/memory.py +158 -53
- agno/os/routers/memory/schemas.py +20 -16
- agno/os/routers/metrics/metrics.py +20 -8
- agno/os/routers/metrics/schemas.py +16 -16
- agno/os/routers/session/session.py +499 -38
- agno/os/schema.py +308 -198
- agno/os/utils.py +401 -41
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +2 -2
- agno/reasoning/deepseek.py +2 -2
- agno/reasoning/default.py +3 -1
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +2 -2
- agno/reasoning/ollama.py +2 -2
- agno/reasoning/openai.py +7 -2
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +248 -94
- agno/run/base.py +44 -5
- agno/run/team.py +238 -97
- agno/run/workflow.py +144 -33
- agno/session/agent.py +105 -89
- agno/session/summary.py +65 -25
- agno/session/team.py +176 -96
- agno/session/workflow.py +406 -40
- agno/team/team.py +3854 -1610
- agno/tools/dalle.py +2 -4
- agno/tools/decorator.py +4 -2
- agno/tools/duckduckgo.py +15 -11
- agno/tools/e2b.py +14 -7
- agno/tools/eleven_labs.py +23 -25
- agno/tools/exa.py +21 -16
- agno/tools/file.py +153 -23
- agno/tools/file_generation.py +350 -0
- agno/tools/firecrawl.py +4 -4
- agno/tools/function.py +250 -30
- agno/tools/gmail.py +238 -14
- agno/tools/google_drive.py +270 -0
- agno/tools/googlecalendar.py +36 -8
- agno/tools/googlesheets.py +20 -5
- agno/tools/jira.py +20 -0
- agno/tools/knowledge.py +3 -3
- agno/tools/mcp/__init__.py +10 -0
- agno/tools/mcp/mcp.py +331 -0
- agno/tools/mcp/multi_mcp.py +347 -0
- agno/tools/mcp/params.py +24 -0
- agno/tools/mcp_toolbox.py +284 -0
- agno/tools/mem0.py +11 -17
- agno/tools/memori.py +1 -53
- agno/tools/memory.py +419 -0
- agno/tools/models/nebius.py +5 -5
- agno/tools/models_labs.py +20 -10
- agno/tools/notion.py +204 -0
- agno/tools/parallel.py +314 -0
- agno/tools/scrapegraph.py +58 -31
- agno/tools/searxng.py +2 -2
- agno/tools/serper.py +2 -2
- agno/tools/slack.py +18 -3
- agno/tools/spider.py +2 -2
- agno/tools/tavily.py +146 -0
- agno/tools/whatsapp.py +1 -1
- agno/tools/workflow.py +278 -0
- agno/tools/yfinance.py +12 -11
- agno/utils/agent.py +820 -0
- agno/utils/audio.py +27 -0
- agno/utils/common.py +90 -1
- agno/utils/events.py +217 -2
- agno/utils/gemini.py +180 -22
- agno/utils/hooks.py +57 -0
- agno/utils/http.py +111 -0
- agno/utils/knowledge.py +12 -5
- agno/utils/log.py +1 -0
- agno/utils/mcp.py +92 -2
- agno/utils/media.py +188 -10
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +60 -0
- agno/utils/models/claude.py +40 -11
- agno/utils/print_response/agent.py +105 -21
- agno/utils/print_response/team.py +103 -38
- agno/utils/print_response/workflow.py +251 -34
- agno/utils/reasoning.py +22 -1
- agno/utils/serialize.py +32 -0
- agno/utils/streamlit.py +16 -10
- agno/utils/string.py +41 -0
- agno/utils/team.py +98 -9
- agno/utils/tools.py +1 -1
- agno/vectordb/base.py +23 -4
- agno/vectordb/cassandra/cassandra.py +65 -9
- agno/vectordb/chroma/chromadb.py +182 -38
- agno/vectordb/clickhouse/clickhousedb.py +64 -11
- agno/vectordb/couchbase/couchbase.py +105 -10
- agno/vectordb/lancedb/lance_db.py +124 -133
- agno/vectordb/langchaindb/langchaindb.py +25 -7
- agno/vectordb/lightrag/lightrag.py +17 -3
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +46 -7
- agno/vectordb/milvus/milvus.py +126 -9
- agno/vectordb/mongodb/__init__.py +7 -1
- agno/vectordb/mongodb/mongodb.py +112 -7
- agno/vectordb/pgvector/pgvector.py +142 -21
- agno/vectordb/pineconedb/pineconedb.py +80 -8
- agno/vectordb/qdrant/qdrant.py +125 -39
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +694 -0
- agno/vectordb/singlestore/singlestore.py +111 -25
- agno/vectordb/surrealdb/surrealdb.py +31 -5
- agno/vectordb/upstashdb/upstashdb.py +76 -8
- agno/vectordb/weaviate/weaviate.py +86 -15
- agno/workflow/__init__.py +2 -0
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +112 -18
- agno/workflow/loop.py +69 -10
- agno/workflow/parallel.py +266 -118
- agno/workflow/router.py +110 -17
- agno/workflow/step.py +638 -129
- agno/workflow/steps.py +65 -6
- agno/workflow/types.py +61 -23
- agno/workflow/workflow.py +2085 -272
- {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/METADATA +182 -58
- agno-2.3.0.dist-info/RECORD +577 -0
- agno/knowledge/reader/url_reader.py +0 -128
- agno/tools/googlesearch.py +0 -98
- agno/tools/mcp.py +0 -610
- agno/utils/models/aws_claude.py +0 -170
- agno-2.0.1.dist-info/RECORD +0 -515
- {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/WHEEL +0 -0
- {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/licenses/LICENSE +0 -0
- {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
from typing import Any, Dict, List, Optional
|
|
2
|
+
from typing import Any, Dict, List, Optional, Union
|
|
3
3
|
|
|
4
4
|
import httpx
|
|
5
5
|
|
|
6
|
+
from agno.filters import FilterExpr
|
|
6
7
|
from agno.knowledge.document import Document
|
|
7
8
|
from agno.utils.log import log_debug, log_error, log_info, log_warning
|
|
8
9
|
from agno.vectordb.base import VectorDb
|
|
@@ -21,9 +22,14 @@ class LightRag(VectorDb):
|
|
|
21
22
|
api_key: Optional[str] = None,
|
|
22
23
|
auth_header_name: str = "X-API-KEY",
|
|
23
24
|
auth_header_format: str = "{api_key}",
|
|
25
|
+
name: Optional[str] = None,
|
|
26
|
+
description: Optional[str] = None,
|
|
24
27
|
):
|
|
25
28
|
self.server_url = server_url
|
|
26
29
|
self.api_key = api_key
|
|
30
|
+
# Initialize base class with name and description
|
|
31
|
+
super().__init__(name=name, description=description)
|
|
32
|
+
|
|
27
33
|
self.auth_header_name = auth_header_name
|
|
28
34
|
self.auth_header_format = auth_header_format
|
|
29
35
|
|
|
@@ -87,14 +93,18 @@ class LightRag(VectorDb):
|
|
|
87
93
|
"""Async upsert documents into the vector database"""
|
|
88
94
|
pass
|
|
89
95
|
|
|
90
|
-
def search(
|
|
96
|
+
def search(
|
|
97
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
98
|
+
) -> List[Document]:
|
|
91
99
|
result = asyncio.run(self.async_search(query, limit=limit, filters=filters))
|
|
92
100
|
return result if result is not None else []
|
|
93
101
|
|
|
94
102
|
async def async_search(
|
|
95
|
-
self, query: str, limit: Optional[int] = None, filters: Optional[Dict[str, Any]] = None
|
|
103
|
+
self, query: str, limit: Optional[int] = None, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
96
104
|
) -> Optional[List[Document]]:
|
|
97
105
|
mode: str = "hybrid" # Default mode, can be "local", "global", or "hybrid"
|
|
106
|
+
if filters is not None:
|
|
107
|
+
log_warning("Filters are not supported in LightRAG. No filters will be applied.")
|
|
98
108
|
try:
|
|
99
109
|
async with httpx.AsyncClient(timeout=30.0) as client:
|
|
100
110
|
response = await client.post(
|
|
@@ -372,3 +382,7 @@ class LightRag(VectorDb):
|
|
|
372
382
|
metadata (Dict[str, Any]): The metadata to update
|
|
373
383
|
"""
|
|
374
384
|
raise NotImplementedError("update_metadata not supported for LightRag - use LightRag's native methods")
|
|
385
|
+
|
|
386
|
+
def get_supported_search_types(self) -> List[str]:
|
|
387
|
+
"""Get the supported search types for this vector database."""
|
|
388
|
+
return [] # LightRag doesn't use SearchType enum
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
from typing import Any, Callable, Dict, List, Optional
|
|
1
|
+
from typing import Any, Callable, Dict, List, Optional, Union
|
|
2
2
|
|
|
3
|
+
from agno.filters import FilterExpr
|
|
3
4
|
from agno.knowledge.document import Document
|
|
4
|
-
from agno.utils.log import logger
|
|
5
|
+
from agno.utils.log import log_warning, logger
|
|
5
6
|
from agno.vectordb.base import VectorDb
|
|
6
7
|
|
|
7
8
|
try:
|
|
@@ -17,6 +18,21 @@ class LlamaIndexVectorDb(VectorDb):
|
|
|
17
18
|
knowledge_retriever: BaseRetriever
|
|
18
19
|
loader: Optional[Callable] = None
|
|
19
20
|
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
knowledge_retriever: BaseRetriever,
|
|
24
|
+
loader: Optional[Callable] = None,
|
|
25
|
+
name: Optional[str] = None,
|
|
26
|
+
description: Optional[str] = None,
|
|
27
|
+
**kwargs,
|
|
28
|
+
):
|
|
29
|
+
super().__init__(**kwargs)
|
|
30
|
+
# Initialize base class with name and description
|
|
31
|
+
super().__init__(name=name, description=description)
|
|
32
|
+
|
|
33
|
+
self.knowledge_retriever = knowledge_retriever
|
|
34
|
+
self.loader = loader
|
|
35
|
+
|
|
20
36
|
def create(self) -> None:
|
|
21
37
|
raise NotImplementedError
|
|
22
38
|
|
|
@@ -54,14 +70,14 @@ class LlamaIndexVectorDb(VectorDb):
|
|
|
54
70
|
raise NotImplementedError
|
|
55
71
|
|
|
56
72
|
def search(
|
|
57
|
-
self, query: str,
|
|
73
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
58
74
|
) -> List[Document]:
|
|
59
75
|
"""
|
|
60
76
|
Returns relevant documents matching the query.
|
|
61
77
|
|
|
62
78
|
Args:
|
|
63
79
|
query (str): The query string to search for.
|
|
64
|
-
|
|
80
|
+
limit (int): The maximum number of documents to return. Defaults to 5.
|
|
65
81
|
filters (Optional[Dict[str, Any]]): Filters to apply to the search. Defaults to None.
|
|
66
82
|
|
|
67
83
|
Returns:
|
|
@@ -69,12 +85,15 @@ class LlamaIndexVectorDb(VectorDb):
|
|
|
69
85
|
Raises:
|
|
70
86
|
ValueError: If the knowledge retriever is not of type BaseRetriever.
|
|
71
87
|
"""
|
|
88
|
+
if filters is not None:
|
|
89
|
+
log_warning("Filters are not supported in LlamaIndex. No filters will be applied.")
|
|
90
|
+
|
|
72
91
|
if not isinstance(self.knowledge_retriever, BaseRetriever):
|
|
73
92
|
raise ValueError(f"Knowledge retriever is not of type BaseRetriever: {self.knowledge_retriever}")
|
|
74
93
|
|
|
75
94
|
lc_documents: List[NodeWithScore] = self.knowledge_retriever.retrieve(query)
|
|
76
|
-
if
|
|
77
|
-
lc_documents = lc_documents[:
|
|
95
|
+
if limit is not None:
|
|
96
|
+
lc_documents = lc_documents[:limit]
|
|
78
97
|
documents = []
|
|
79
98
|
for lc_doc in lc_documents:
|
|
80
99
|
documents.append(
|
|
@@ -86,7 +105,7 @@ class LlamaIndexVectorDb(VectorDb):
|
|
|
86
105
|
return documents
|
|
87
106
|
|
|
88
107
|
async def async_search(
|
|
89
|
-
self, query: str, limit: int = 5, filters: Optional[Dict[str, Any]] = None
|
|
108
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
90
109
|
) -> List[Document]:
|
|
91
110
|
return self.search(query, limit, filters)
|
|
92
111
|
|
|
@@ -125,3 +144,23 @@ class LlamaIndexVectorDb(VectorDb):
|
|
|
125
144
|
metadata (Dict[str, Any]): The metadata to update
|
|
126
145
|
"""
|
|
127
146
|
raise NotImplementedError("update_metadata not supported for LlamaIndex vectorstores")
|
|
147
|
+
|
|
148
|
+
def delete_by_content_id(self, content_id: str) -> bool:
|
|
149
|
+
"""
|
|
150
|
+
Delete documents by content ID.
|
|
151
|
+
Not implemented for LlamaIndex wrapper.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
content_id (str): The content ID to delete
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
bool: False as this operation is not supported
|
|
158
|
+
"""
|
|
159
|
+
logger.warning(
|
|
160
|
+
"LlamaIndexVectorDb.delete_by_content_id() not supported - please check the vectorstore manually."
|
|
161
|
+
)
|
|
162
|
+
return False
|
|
163
|
+
|
|
164
|
+
def get_supported_search_types(self) -> List[str]:
|
|
165
|
+
"""Get the supported search types for this vector database."""
|
|
166
|
+
return [] # LlamaIndexVectorDb doesn't use SearchType enum
|
agno/vectordb/milvus/milvus.py
CHANGED
|
@@ -9,10 +9,11 @@ try:
|
|
|
9
9
|
except ImportError:
|
|
10
10
|
raise ImportError("The `pymilvus` package is not installed. Please install it via `pip install pymilvus`.")
|
|
11
11
|
|
|
12
|
+
from agno.filters import FilterExpr
|
|
12
13
|
from agno.knowledge.document import Document
|
|
13
14
|
from agno.knowledge.embedder import Embedder
|
|
14
15
|
from agno.knowledge.reranker.base import Reranker
|
|
15
|
-
from agno.utils.log import log_debug, log_error, log_info
|
|
16
|
+
from agno.utils.log import log_debug, log_error, log_info, log_warning
|
|
16
17
|
from agno.vectordb.base import VectorDb
|
|
17
18
|
from agno.vectordb.distance import Distance
|
|
18
19
|
from agno.vectordb.search import SearchType
|
|
@@ -28,6 +29,9 @@ class Milvus(VectorDb):
|
|
|
28
29
|
def __init__(
|
|
29
30
|
self,
|
|
30
31
|
collection: str,
|
|
32
|
+
name: Optional[str] = None,
|
|
33
|
+
description: Optional[str] = None,
|
|
34
|
+
id: Optional[str] = None,
|
|
31
35
|
embedder: Optional[Embedder] = None,
|
|
32
36
|
distance: Distance = Distance.cosine,
|
|
33
37
|
uri: str = "http://localhost:19530",
|
|
@@ -42,6 +46,8 @@ class Milvus(VectorDb):
|
|
|
42
46
|
|
|
43
47
|
Args:
|
|
44
48
|
collection (str): Name of the Milvus collection.
|
|
49
|
+
name (Optional[str]): Name of the vector database.
|
|
50
|
+
description (Optional[str]): Description of the vector database.
|
|
45
51
|
embedder (Embedder): Embedder to use for embedding documents.
|
|
46
52
|
distance (Distance): Distance metric to use for vector similarity.
|
|
47
53
|
uri (Optional[str]): URI of the Milvus server.
|
|
@@ -63,6 +69,20 @@ class Milvus(VectorDb):
|
|
|
63
69
|
reranker (Optional[Reranker]): Reranker to use for hybrid search results
|
|
64
70
|
**kwargs: Additional keyword arguments to pass to the MilvusClient.
|
|
65
71
|
"""
|
|
72
|
+
# Validate required parameters
|
|
73
|
+
if not collection:
|
|
74
|
+
raise ValueError("Collection name must be provided.")
|
|
75
|
+
|
|
76
|
+
# Dynamic ID generation based on unique identifiers
|
|
77
|
+
if id is None:
|
|
78
|
+
from agno.utils.string import generate_id
|
|
79
|
+
|
|
80
|
+
seed = f"{uri or 'milvus'}#{collection}"
|
|
81
|
+
id = generate_id(seed)
|
|
82
|
+
|
|
83
|
+
# Initialize base class with name, description, and generated ID
|
|
84
|
+
super().__init__(id=id, name=name, description=description)
|
|
85
|
+
|
|
66
86
|
self.collection: str = collection
|
|
67
87
|
|
|
68
88
|
if embedder is None:
|
|
@@ -423,6 +443,9 @@ class Milvus(VectorDb):
|
|
|
423
443
|
else:
|
|
424
444
|
for document in documents:
|
|
425
445
|
document.embed(embedder=self.embedder)
|
|
446
|
+
if not document.embedding:
|
|
447
|
+
log_debug(f"Skipping document without embedding: {document.name} ({document.meta_data})")
|
|
448
|
+
continue
|
|
426
449
|
cleaned_content = document.content.replace("\x00", "\ufffd")
|
|
427
450
|
doc_id = md5(cleaned_content.encode()).hexdigest()
|
|
428
451
|
|
|
@@ -454,8 +477,44 @@ class Milvus(VectorDb):
|
|
|
454
477
|
"""Insert documents asynchronously based on search type."""
|
|
455
478
|
log_info(f"Inserting {len(documents)} documents asynchronously")
|
|
456
479
|
|
|
457
|
-
|
|
458
|
-
|
|
480
|
+
if self.embedder.enable_batch and hasattr(self.embedder, "async_get_embeddings_batch_and_usage"):
|
|
481
|
+
# Use batch embedding when enabled and supported
|
|
482
|
+
try:
|
|
483
|
+
# Extract content from all documents
|
|
484
|
+
doc_contents = [doc.content for doc in documents]
|
|
485
|
+
|
|
486
|
+
# Get batch embeddings and usage
|
|
487
|
+
embeddings, usages = await self.embedder.async_get_embeddings_batch_and_usage(doc_contents)
|
|
488
|
+
|
|
489
|
+
# Process documents with pre-computed embeddings
|
|
490
|
+
for j, doc in enumerate(documents):
|
|
491
|
+
try:
|
|
492
|
+
if j < len(embeddings):
|
|
493
|
+
doc.embedding = embeddings[j]
|
|
494
|
+
doc.usage = usages[j] if j < len(usages) else None
|
|
495
|
+
except Exception as e:
|
|
496
|
+
log_error(f"Error assigning batch embedding to document '{doc.name}': {e}")
|
|
497
|
+
|
|
498
|
+
except Exception as e:
|
|
499
|
+
# Check if this is a rate limit error - don't fall back as it would make things worse
|
|
500
|
+
error_str = str(e).lower()
|
|
501
|
+
is_rate_limit = any(
|
|
502
|
+
phrase in error_str
|
|
503
|
+
for phrase in ["rate limit", "too many requests", "429", "trial key", "api calls / minute"]
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
if is_rate_limit:
|
|
507
|
+
log_error(f"Rate limit detected during batch embedding. {e}")
|
|
508
|
+
raise e
|
|
509
|
+
else:
|
|
510
|
+
log_error(f"Async batch embedding failed, falling back to individual embeddings: {e}")
|
|
511
|
+
# Fall back to individual embedding
|
|
512
|
+
embed_tasks = [doc.async_embed(embedder=self.embedder) for doc in documents]
|
|
513
|
+
await asyncio.gather(*embed_tasks, return_exceptions=True)
|
|
514
|
+
else:
|
|
515
|
+
# Use individual embedding
|
|
516
|
+
embed_tasks = [document.async_embed(embedder=self.embedder) for document in documents]
|
|
517
|
+
await asyncio.gather(*embed_tasks, return_exceptions=True)
|
|
459
518
|
|
|
460
519
|
if self.search_type == SearchType.hybrid:
|
|
461
520
|
await asyncio.gather(
|
|
@@ -465,6 +524,9 @@ class Milvus(VectorDb):
|
|
|
465
524
|
|
|
466
525
|
async def process_document(document):
|
|
467
526
|
document.embed(embedder=self.embedder)
|
|
527
|
+
if not document.embedding:
|
|
528
|
+
log_debug(f"Skipping document without embedding: {document.name} ({document.meta_data})")
|
|
529
|
+
return None
|
|
468
530
|
cleaned_content = document.content.replace("\x00", "\ufffd")
|
|
469
531
|
doc_id = md5(cleaned_content.encode()).hexdigest()
|
|
470
532
|
|
|
@@ -541,8 +603,44 @@ class Milvus(VectorDb):
|
|
|
541
603
|
) -> None:
|
|
542
604
|
log_debug(f"Upserting {len(documents)} documents asynchronously")
|
|
543
605
|
|
|
544
|
-
|
|
545
|
-
|
|
606
|
+
if self.embedder.enable_batch and hasattr(self.embedder, "async_get_embeddings_batch_and_usage"):
|
|
607
|
+
# Use batch embedding when enabled and supported
|
|
608
|
+
try:
|
|
609
|
+
# Extract content from all documents
|
|
610
|
+
doc_contents = [doc.content for doc in documents]
|
|
611
|
+
|
|
612
|
+
# Get batch embeddings and usage
|
|
613
|
+
embeddings, usages = await self.embedder.async_get_embeddings_batch_and_usage(doc_contents)
|
|
614
|
+
|
|
615
|
+
# Process documents with pre-computed embeddings
|
|
616
|
+
for j, doc in enumerate(documents):
|
|
617
|
+
try:
|
|
618
|
+
if j < len(embeddings):
|
|
619
|
+
doc.embedding = embeddings[j]
|
|
620
|
+
doc.usage = usages[j] if j < len(usages) else None
|
|
621
|
+
except Exception as e:
|
|
622
|
+
log_error(f"Error assigning batch embedding to document '{doc.name}': {e}")
|
|
623
|
+
|
|
624
|
+
except Exception as e:
|
|
625
|
+
# Check if this is a rate limit error - don't fall back as it would make things worse
|
|
626
|
+
error_str = str(e).lower()
|
|
627
|
+
is_rate_limit = any(
|
|
628
|
+
phrase in error_str
|
|
629
|
+
for phrase in ["rate limit", "too many requests", "429", "trial key", "api calls / minute"]
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
if is_rate_limit:
|
|
633
|
+
log_error(f"Rate limit detected during batch embedding. {e}")
|
|
634
|
+
raise e
|
|
635
|
+
else:
|
|
636
|
+
log_error(f"Async batch embedding failed, falling back to individual embeddings: {e}")
|
|
637
|
+
# Fall back to individual embedding
|
|
638
|
+
embed_tasks = [doc.async_embed(embedder=self.embedder) for doc in documents]
|
|
639
|
+
await asyncio.gather(*embed_tasks, return_exceptions=True)
|
|
640
|
+
else:
|
|
641
|
+
# Use individual embedding
|
|
642
|
+
embed_tasks = [document.async_embed(embedder=self.embedder) for document in documents]
|
|
643
|
+
await asyncio.gather(*embed_tasks, return_exceptions=True)
|
|
546
644
|
|
|
547
645
|
async def process_document(document):
|
|
548
646
|
cleaned_content = document.content.replace("\x00", "\ufffd")
|
|
@@ -578,7 +676,9 @@ class Milvus(VectorDb):
|
|
|
578
676
|
"""
|
|
579
677
|
return MILVUS_DISTANCE_MAP.get(self.distance, "COSINE")
|
|
580
678
|
|
|
581
|
-
def search(
|
|
679
|
+
def search(
|
|
680
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
681
|
+
) -> List[Document]:
|
|
582
682
|
"""
|
|
583
683
|
Search for documents matching the query.
|
|
584
684
|
|
|
@@ -590,6 +690,9 @@ class Milvus(VectorDb):
|
|
|
590
690
|
Returns:
|
|
591
691
|
List[Document]: List of matching documents
|
|
592
692
|
"""
|
|
693
|
+
if isinstance(filters, List):
|
|
694
|
+
log_warning("Filters Expressions are not supported in Milvus. No filters will be applied.")
|
|
695
|
+
filters = None
|
|
593
696
|
if self.search_type == SearchType.hybrid:
|
|
594
697
|
return self.hybrid_search(query, limit)
|
|
595
698
|
|
|
@@ -622,12 +725,20 @@ class Milvus(VectorDb):
|
|
|
622
725
|
)
|
|
623
726
|
)
|
|
624
727
|
|
|
728
|
+
# Apply reranker if available
|
|
729
|
+
if self.reranker and search_results:
|
|
730
|
+
search_results = self.reranker.rerank(query=query, documents=search_results)
|
|
731
|
+
search_results = search_results[:limit]
|
|
732
|
+
|
|
625
733
|
log_info(f"Found {len(search_results)} documents")
|
|
626
734
|
return search_results
|
|
627
735
|
|
|
628
736
|
async def async_search(
|
|
629
|
-
self, query: str, limit: int = 5, filters: Optional[Dict[str, Any]] = None
|
|
737
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
630
738
|
) -> List[Document]:
|
|
739
|
+
if isinstance(filters, List):
|
|
740
|
+
log_warning("Filters Expressions are not supported in Milvus. No filters will be applied.")
|
|
741
|
+
filters = None
|
|
631
742
|
if self.search_type == SearchType.hybrid:
|
|
632
743
|
return await self.async_hybrid_search(query, limit, filters)
|
|
633
744
|
|
|
@@ -663,7 +774,9 @@ class Milvus(VectorDb):
|
|
|
663
774
|
log_info(f"Found {len(search_results)} documents")
|
|
664
775
|
return search_results
|
|
665
776
|
|
|
666
|
-
def hybrid_search(
|
|
777
|
+
def hybrid_search(
|
|
778
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
779
|
+
) -> List[Document]:
|
|
667
780
|
"""
|
|
668
781
|
Perform a hybrid search combining dense and sparse vector similarity.
|
|
669
782
|
|
|
@@ -755,7 +868,7 @@ class Milvus(VectorDb):
|
|
|
755
868
|
return []
|
|
756
869
|
|
|
757
870
|
async def async_hybrid_search(
|
|
758
|
-
self, query: str, limit: int = 5, filters: Optional[Dict[str, Any]] = None
|
|
871
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
759
872
|
) -> List[Document]:
|
|
760
873
|
"""
|
|
761
874
|
Perform an asynchronous hybrid search combining dense and sparse vector similarity.
|
|
@@ -1063,3 +1176,7 @@ class Milvus(VectorDb):
|
|
|
1063
1176
|
except Exception as e:
|
|
1064
1177
|
log_error(f"Error updating metadata for content_id '{content_id}': {e}")
|
|
1065
1178
|
raise
|
|
1179
|
+
|
|
1180
|
+
def get_supported_search_types(self) -> List[str]:
|
|
1181
|
+
"""Get the supported search types for this vector database."""
|
|
1182
|
+
return [SearchType.vector, SearchType.hybrid]
|
agno/vectordb/mongodb/mongodb.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import time
|
|
3
|
-
from typing import Any, Dict, List, Optional
|
|
3
|
+
from typing import Any, Dict, List, Optional, Union
|
|
4
4
|
|
|
5
5
|
from bson import ObjectId
|
|
6
6
|
|
|
7
|
+
from agno.filters import FilterExpr
|
|
7
8
|
from agno.knowledge.document import Document
|
|
8
9
|
from agno.knowledge.embedder import Embedder
|
|
9
10
|
from agno.utils.log import log_debug, log_info, log_warning, logger
|
|
@@ -33,6 +34,9 @@ class MongoDb(VectorDb):
|
|
|
33
34
|
def __init__(
|
|
34
35
|
self,
|
|
35
36
|
collection_name: str,
|
|
37
|
+
name: Optional[str] = None,
|
|
38
|
+
description: Optional[str] = None,
|
|
39
|
+
id: Optional[str] = None,
|
|
36
40
|
db_url: Optional[str] = "mongodb://localhost:27017/",
|
|
37
41
|
database: str = "agno",
|
|
38
42
|
embedder: Optional[Embedder] = None,
|
|
@@ -56,6 +60,8 @@ class MongoDb(VectorDb):
|
|
|
56
60
|
|
|
57
61
|
Args:
|
|
58
62
|
collection_name (str): Name of the MongoDB collection.
|
|
63
|
+
name (Optional[str]): Name of the vector database.
|
|
64
|
+
description (Optional[str]): Description of the vector database.
|
|
59
65
|
db_url (Optional[str]): MongoDB connection string.
|
|
60
66
|
database (str): Database name.
|
|
61
67
|
embedder (Embedder): Embedder instance for generating embeddings.
|
|
@@ -74,11 +80,24 @@ class MongoDb(VectorDb):
|
|
|
74
80
|
hybrid_rank_constant (int): Default rank constant (k) for Reciprocal Rank Fusion in hybrid search. This constant is added to the rank before taking the reciprocal, helping to smooth scores. A common value is 60.
|
|
75
81
|
**kwargs: Additional arguments for MongoClient.
|
|
76
82
|
"""
|
|
83
|
+
# Validate required parameters
|
|
77
84
|
if not collection_name:
|
|
78
85
|
raise ValueError("Collection name must not be empty.")
|
|
79
86
|
if not database:
|
|
80
87
|
raise ValueError("Database name must not be empty.")
|
|
88
|
+
|
|
89
|
+
# Dynamic ID generation based on unique identifiers
|
|
90
|
+
if id is None:
|
|
91
|
+
from agno.utils.string import generate_id
|
|
92
|
+
|
|
93
|
+
connection_identifier = db_url or "mongodb://localhost:27017/"
|
|
94
|
+
seed = f"{connection_identifier}#{database}#{collection_name}"
|
|
95
|
+
id = generate_id(seed)
|
|
96
|
+
|
|
81
97
|
self.collection_name = collection_name
|
|
98
|
+
# Initialize base class with name, description, and generated ID
|
|
99
|
+
super().__init__(id=id, name=name, description=description)
|
|
100
|
+
|
|
82
101
|
self.database = database
|
|
83
102
|
self.search_index_name = search_index_name
|
|
84
103
|
self.cosmos_compatibility = cosmos_compatibility
|
|
@@ -567,9 +586,16 @@ class MongoDb(VectorDb):
|
|
|
567
586
|
return True
|
|
568
587
|
|
|
569
588
|
def search(
|
|
570
|
-
self,
|
|
589
|
+
self,
|
|
590
|
+
query: str,
|
|
591
|
+
limit: int = 5,
|
|
592
|
+
filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
593
|
+
min_score: float = 0.0,
|
|
571
594
|
) -> List[Document]:
|
|
572
595
|
"""Search for documents using vector similarity."""
|
|
596
|
+
if isinstance(filters, List):
|
|
597
|
+
log_warning("Filters Expressions are not supported in MongoDB. No filters will be applied.")
|
|
598
|
+
filters = None
|
|
573
599
|
if self.search_type == SearchType.hybrid:
|
|
574
600
|
return self.hybrid_search(query, limit=limit, filters=filters)
|
|
575
601
|
|
|
@@ -1018,8 +1044,44 @@ class MongoDb(VectorDb):
|
|
|
1018
1044
|
log_debug(f"Inserting {len(documents)} documents asynchronously")
|
|
1019
1045
|
collection = await self._get_async_collection()
|
|
1020
1046
|
|
|
1021
|
-
|
|
1022
|
-
|
|
1047
|
+
if self.embedder.enable_batch and hasattr(self.embedder, "async_get_embeddings_batch_and_usage"):
|
|
1048
|
+
# Use batch embedding when enabled and supported
|
|
1049
|
+
try:
|
|
1050
|
+
# Extract content from all documents
|
|
1051
|
+
doc_contents = [doc.content for doc in documents]
|
|
1052
|
+
|
|
1053
|
+
# Get batch embeddings and usage
|
|
1054
|
+
embeddings, usages = await self.embedder.async_get_embeddings_batch_and_usage(doc_contents)
|
|
1055
|
+
|
|
1056
|
+
# Process documents with pre-computed embeddings
|
|
1057
|
+
for j, doc in enumerate(documents):
|
|
1058
|
+
try:
|
|
1059
|
+
if j < len(embeddings):
|
|
1060
|
+
doc.embedding = embeddings[j]
|
|
1061
|
+
doc.usage = usages[j] if j < len(usages) else None
|
|
1062
|
+
except Exception as e:
|
|
1063
|
+
logger.error(f"Error assigning batch embedding to document '{doc.name}': {e}")
|
|
1064
|
+
|
|
1065
|
+
except Exception as e:
|
|
1066
|
+
# Check if this is a rate limit error - don't fall back as it would make things worse
|
|
1067
|
+
error_str = str(e).lower()
|
|
1068
|
+
is_rate_limit = any(
|
|
1069
|
+
phrase in error_str
|
|
1070
|
+
for phrase in ["rate limit", "too many requests", "429", "trial key", "api calls / minute"]
|
|
1071
|
+
)
|
|
1072
|
+
|
|
1073
|
+
if is_rate_limit:
|
|
1074
|
+
logger.error(f"Rate limit detected during batch embedding. {e}")
|
|
1075
|
+
raise e
|
|
1076
|
+
else:
|
|
1077
|
+
logger.warning(f"Async batch embedding failed, falling back to individual embeddings: {e}")
|
|
1078
|
+
# Fall back to individual embedding
|
|
1079
|
+
embed_tasks = [doc.async_embed(embedder=self.embedder) for doc in documents]
|
|
1080
|
+
await asyncio.gather(*embed_tasks, return_exceptions=True)
|
|
1081
|
+
else:
|
|
1082
|
+
# Use individual embedding
|
|
1083
|
+
embed_tasks = [document.async_embed(embedder=self.embedder) for document in documents]
|
|
1084
|
+
await asyncio.gather(*embed_tasks, return_exceptions=True)
|
|
1023
1085
|
|
|
1024
1086
|
prepared_docs = []
|
|
1025
1087
|
for document in documents:
|
|
@@ -1047,8 +1109,44 @@ class MongoDb(VectorDb):
|
|
|
1047
1109
|
log_info(f"Upserting {len(documents)} documents asynchronously")
|
|
1048
1110
|
collection = await self._get_async_collection()
|
|
1049
1111
|
|
|
1050
|
-
|
|
1051
|
-
|
|
1112
|
+
if self.embedder.enable_batch and hasattr(self.embedder, "async_get_embeddings_batch_and_usage"):
|
|
1113
|
+
# Use batch embedding when enabled and supported
|
|
1114
|
+
try:
|
|
1115
|
+
# Extract content from all documents
|
|
1116
|
+
doc_contents = [doc.content for doc in documents]
|
|
1117
|
+
|
|
1118
|
+
# Get batch embeddings and usage
|
|
1119
|
+
embeddings, usages = await self.embedder.async_get_embeddings_batch_and_usage(doc_contents)
|
|
1120
|
+
|
|
1121
|
+
# Process documents with pre-computed embeddings
|
|
1122
|
+
for j, doc in enumerate(documents):
|
|
1123
|
+
try:
|
|
1124
|
+
if j < len(embeddings):
|
|
1125
|
+
doc.embedding = embeddings[j]
|
|
1126
|
+
doc.usage = usages[j] if j < len(usages) else None
|
|
1127
|
+
except Exception as e:
|
|
1128
|
+
logger.error(f"Error assigning batch embedding to document '{doc.name}': {e}")
|
|
1129
|
+
|
|
1130
|
+
except Exception as e:
|
|
1131
|
+
# Check if this is a rate limit error - don't fall back as it would make things worse
|
|
1132
|
+
error_str = str(e).lower()
|
|
1133
|
+
is_rate_limit = any(
|
|
1134
|
+
phrase in error_str
|
|
1135
|
+
for phrase in ["rate limit", "too many requests", "429", "trial key", "api calls / minute"]
|
|
1136
|
+
)
|
|
1137
|
+
|
|
1138
|
+
if is_rate_limit:
|
|
1139
|
+
logger.error(f"Rate limit detected during batch embedding. {e}")
|
|
1140
|
+
raise e
|
|
1141
|
+
else:
|
|
1142
|
+
logger.warning(f"Async batch embedding failed, falling back to individual embeddings: {e}")
|
|
1143
|
+
# Fall back to individual embedding
|
|
1144
|
+
embed_tasks = [doc.async_embed(embedder=self.embedder) for doc in documents]
|
|
1145
|
+
await asyncio.gather(*embed_tasks, return_exceptions=True)
|
|
1146
|
+
else:
|
|
1147
|
+
# Use individual embedding
|
|
1148
|
+
embed_tasks = [document.async_embed(embedder=self.embedder) for document in documents]
|
|
1149
|
+
await asyncio.gather(*embed_tasks, return_exceptions=True)
|
|
1052
1150
|
|
|
1053
1151
|
for document in documents:
|
|
1054
1152
|
try:
|
|
@@ -1063,9 +1161,12 @@ class MongoDb(VectorDb):
|
|
|
1063
1161
|
logger.error(f"Error upserting document '{document.name}' asynchronously: {e}")
|
|
1064
1162
|
|
|
1065
1163
|
async def async_search(
|
|
1066
|
-
self, query: str, limit: int = 5, filters: Optional[Dict[str, Any]] = None
|
|
1164
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
1067
1165
|
) -> List[Document]:
|
|
1068
1166
|
"""Search for documents asynchronously."""
|
|
1167
|
+
if isinstance(filters, List):
|
|
1168
|
+
log_warning("Filters Expressions are not supported in MongoDB. No filters will be applied.")
|
|
1169
|
+
filters = None
|
|
1069
1170
|
query_embedding = self.embedder.get_embedding(query)
|
|
1070
1171
|
if query_embedding is None:
|
|
1071
1172
|
logger.error(f"Failed to generate embedding for query: {query}")
|
|
@@ -1310,3 +1411,7 @@ class MongoDb(VectorDb):
|
|
|
1310
1411
|
except Exception as e:
|
|
1311
1412
|
logger.error(f"Error updating metadata for content_id '{content_id}': {e}")
|
|
1312
1413
|
raise
|
|
1414
|
+
|
|
1415
|
+
def get_supported_search_types(self) -> List[str]:
|
|
1416
|
+
"""Get the supported search types for this vector database."""
|
|
1417
|
+
return [SearchType.vector, SearchType.hybrid]
|