agno 0.1.2__py3-none-any.whl → 2.3.13__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/__init__.py +8 -0
- agno/agent/__init__.py +44 -5
- agno/agent/agent.py +10531 -2975
- agno/api/agent.py +14 -53
- agno/api/api.py +7 -46
- agno/api/evals.py +22 -0
- agno/api/os.py +17 -0
- agno/api/routes.py +6 -25
- agno/api/schemas/__init__.py +9 -0
- agno/api/schemas/agent.py +6 -9
- agno/api/schemas/evals.py +16 -0
- agno/api/schemas/os.py +14 -0
- agno/api/schemas/team.py +10 -10
- agno/api/schemas/utils.py +21 -0
- agno/api/schemas/workflows.py +16 -0
- agno/api/settings.py +53 -0
- agno/api/team.py +22 -26
- agno/api/workflow.py +28 -0
- agno/cloud/aws/base.py +214 -0
- agno/cloud/aws/s3/__init__.py +2 -0
- agno/cloud/aws/s3/api_client.py +43 -0
- agno/cloud/aws/s3/bucket.py +195 -0
- agno/cloud/aws/s3/object.py +57 -0
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/__init__.py +24 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +946 -0
- agno/db/dynamo/__init__.py +3 -0
- agno/db/dynamo/dynamo.py +2781 -0
- agno/db/dynamo/schemas.py +442 -0
- agno/db/dynamo/utils.py +743 -0
- agno/db/firestore/__init__.py +3 -0
- agno/db/firestore/firestore.py +2379 -0
- agno/db/firestore/schemas.py +181 -0
- agno/db/firestore/utils.py +376 -0
- agno/db/gcs_json/__init__.py +3 -0
- agno/db/gcs_json/gcs_json_db.py +1791 -0
- agno/db/gcs_json/utils.py +228 -0
- agno/db/in_memory/__init__.py +3 -0
- agno/db/in_memory/in_memory_db.py +1312 -0
- agno/db/in_memory/utils.py +230 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1777 -0
- agno/db/json/utils.py +230 -0
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +635 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +17 -0
- agno/db/mongo/async_mongo.py +2760 -0
- agno/db/mongo/mongo.py +2597 -0
- agno/db/mongo/schemas.py +119 -0
- agno/db/mongo/utils.py +276 -0
- agno/db/mysql/__init__.py +4 -0
- agno/db/mysql/async_mysql.py +2912 -0
- agno/db/mysql/mysql.py +2923 -0
- agno/db/mysql/schemas.py +186 -0
- agno/db/mysql/utils.py +488 -0
- agno/db/postgres/__init__.py +4 -0
- agno/db/postgres/async_postgres.py +2579 -0
- agno/db/postgres/postgres.py +2870 -0
- agno/db/postgres/schemas.py +187 -0
- agno/db/postgres/utils.py +442 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +2141 -0
- agno/db/redis/schemas.py +159 -0
- agno/db/redis/utils.py +346 -0
- agno/db/schemas/__init__.py +4 -0
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/evals.py +34 -0
- agno/db/schemas/knowledge.py +40 -0
- agno/db/schemas/memory.py +61 -0
- agno/db/singlestore/__init__.py +3 -0
- agno/db/singlestore/schemas.py +179 -0
- agno/db/singlestore/singlestore.py +2877 -0
- agno/db/singlestore/utils.py +384 -0
- agno/db/sqlite/__init__.py +4 -0
- agno/db/sqlite/async_sqlite.py +2911 -0
- agno/db/sqlite/schemas.py +181 -0
- agno/db/sqlite/sqlite.py +2908 -0
- agno/db/sqlite/utils.py +429 -0
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +334 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1908 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +118 -0
- agno/eval/__init__.py +24 -0
- agno/eval/accuracy.py +666 -276
- agno/eval/agent_as_judge.py +861 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +779 -0
- agno/eval/reliability.py +241 -62
- agno/eval/utils.py +120 -0
- agno/exceptions.py +143 -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/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/__init__.py +3 -0
- agno/integrations/discord/client.py +203 -0
- agno/knowledge/__init__.py +5 -1
- agno/{document → knowledge}/chunking/agentic.py +22 -14
- agno/{document → knowledge}/chunking/document.py +2 -2
- agno/{document → knowledge}/chunking/fixed.py +7 -6
- agno/knowledge/chunking/markdown.py +151 -0
- agno/{document → knowledge}/chunking/recursive.py +15 -3
- agno/knowledge/chunking/row.py +39 -0
- agno/knowledge/chunking/semantic.py +91 -0
- agno/knowledge/chunking/strategy.py +165 -0
- agno/knowledge/content.py +74 -0
- agno/knowledge/document/__init__.py +5 -0
- agno/{document → knowledge/document}/base.py +12 -2
- agno/knowledge/embedder/__init__.py +5 -0
- agno/knowledge/embedder/aws_bedrock.py +343 -0
- agno/knowledge/embedder/azure_openai.py +210 -0
- agno/{embedder → knowledge/embedder}/base.py +8 -0
- agno/knowledge/embedder/cohere.py +323 -0
- agno/knowledge/embedder/fastembed.py +62 -0
- agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
- agno/knowledge/embedder/google.py +258 -0
- agno/knowledge/embedder/huggingface.py +94 -0
- agno/knowledge/embedder/jina.py +182 -0
- agno/knowledge/embedder/langdb.py +22 -0
- agno/knowledge/embedder/mistral.py +206 -0
- agno/knowledge/embedder/nebius.py +13 -0
- agno/knowledge/embedder/ollama.py +154 -0
- agno/knowledge/embedder/openai.py +195 -0
- agno/knowledge/embedder/sentence_transformer.py +63 -0
- agno/{embedder → knowledge/embedder}/together.py +1 -1
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +165 -0
- agno/knowledge/knowledge.py +3006 -0
- agno/knowledge/reader/__init__.py +7 -0
- agno/knowledge/reader/arxiv_reader.py +81 -0
- agno/knowledge/reader/base.py +95 -0
- agno/knowledge/reader/csv_reader.py +164 -0
- agno/knowledge/reader/docx_reader.py +82 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/firecrawl_reader.py +201 -0
- agno/knowledge/reader/json_reader.py +88 -0
- agno/knowledge/reader/markdown_reader.py +137 -0
- agno/knowledge/reader/pdf_reader.py +431 -0
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +313 -0
- agno/knowledge/reader/s3_reader.py +89 -0
- agno/knowledge/reader/tavily_reader.py +193 -0
- agno/knowledge/reader/text_reader.py +127 -0
- agno/knowledge/reader/web_search_reader.py +325 -0
- agno/knowledge/reader/website_reader.py +455 -0
- agno/knowledge/reader/wikipedia_reader.py +91 -0
- agno/knowledge/reader/youtube_reader.py +78 -0
- agno/knowledge/remote_content/remote_content.py +88 -0
- agno/knowledge/reranker/__init__.py +3 -0
- agno/{reranker → knowledge/reranker}/base.py +1 -1
- agno/{reranker → knowledge/reranker}/cohere.py +2 -2
- agno/knowledge/reranker/infinity.py +195 -0
- agno/knowledge/reranker/sentence_transformer.py +54 -0
- agno/knowledge/types.py +39 -0
- agno/knowledge/utils.py +234 -0
- agno/media.py +439 -95
- agno/memory/__init__.py +16 -3
- agno/memory/manager.py +1474 -123
- agno/memory/strategies/__init__.py +15 -0
- agno/memory/strategies/base.py +66 -0
- agno/memory/strategies/summarize.py +196 -0
- agno/memory/strategies/types.py +37 -0
- agno/models/aimlapi/__init__.py +5 -0
- agno/models/aimlapi/aimlapi.py +62 -0
- agno/models/anthropic/__init__.py +4 -0
- agno/models/anthropic/claude.py +960 -496
- agno/models/aws/__init__.py +15 -0
- agno/models/aws/bedrock.py +686 -451
- agno/models/aws/claude.py +190 -183
- agno/models/azure/__init__.py +18 -1
- agno/models/azure/ai_foundry.py +489 -0
- agno/models/azure/openai_chat.py +89 -40
- agno/models/base.py +2477 -550
- agno/models/cerebras/__init__.py +12 -0
- agno/models/cerebras/cerebras.py +565 -0
- agno/models/cerebras/cerebras_openai.py +131 -0
- agno/models/cohere/__init__.py +4 -0
- agno/models/cohere/chat.py +306 -492
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +74 -0
- agno/models/dashscope/__init__.py +5 -0
- agno/models/dashscope/dashscope.py +90 -0
- agno/models/deepinfra/__init__.py +5 -0
- agno/models/deepinfra/deepinfra.py +45 -0
- agno/models/deepseek/__init__.py +4 -0
- agno/models/deepseek/deepseek.py +110 -9
- agno/models/fireworks/__init__.py +4 -0
- agno/models/fireworks/fireworks.py +19 -22
- agno/models/google/__init__.py +3 -7
- agno/models/google/gemini.py +1717 -662
- agno/models/google/utils.py +22 -0
- agno/models/groq/__init__.py +4 -0
- agno/models/groq/groq.py +391 -666
- agno/models/huggingface/__init__.py +4 -0
- agno/models/huggingface/huggingface.py +266 -538
- agno/models/ibm/__init__.py +5 -0
- agno/models/ibm/watsonx.py +432 -0
- agno/models/internlm/__init__.py +3 -0
- agno/models/internlm/internlm.py +20 -3
- agno/models/langdb/__init__.py +1 -0
- agno/models/langdb/langdb.py +60 -0
- agno/models/litellm/__init__.py +14 -0
- agno/models/litellm/chat.py +503 -0
- agno/models/litellm/litellm_openai.py +42 -0
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/lmstudio/__init__.py +5 -0
- agno/models/lmstudio/lmstudio.py +25 -0
- agno/models/message.py +361 -39
- agno/models/meta/__init__.py +12 -0
- agno/models/meta/llama.py +502 -0
- agno/models/meta/llama_openai.py +79 -0
- agno/models/metrics.py +120 -0
- agno/models/mistral/__init__.py +4 -0
- agno/models/mistral/mistral.py +293 -393
- agno/models/nebius/__init__.py +3 -0
- agno/models/nebius/nebius.py +53 -0
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/__init__.py +4 -0
- agno/models/nvidia/nvidia.py +22 -3
- agno/models/ollama/__init__.py +4 -2
- agno/models/ollama/chat.py +257 -492
- agno/models/openai/__init__.py +7 -0
- agno/models/openai/chat.py +725 -770
- agno/models/openai/like.py +16 -2
- agno/models/openai/responses.py +1121 -0
- agno/models/openrouter/__init__.py +4 -0
- agno/models/openrouter/openrouter.py +62 -5
- agno/models/perplexity/__init__.py +5 -0
- agno/models/perplexity/perplexity.py +203 -0
- agno/models/portkey/__init__.py +3 -0
- agno/models/portkey/portkey.py +82 -0
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +69 -0
- agno/models/response.py +177 -7
- agno/models/sambanova/__init__.py +4 -0
- agno/models/sambanova/sambanova.py +23 -4
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +42 -0
- agno/models/together/__init__.py +4 -0
- agno/models/together/together.py +21 -164
- agno/models/utils.py +266 -0
- agno/models/vercel/__init__.py +3 -0
- agno/models/vercel/v0.py +43 -0
- agno/models/vertexai/__init__.py +0 -1
- agno/models/vertexai/claude.py +190 -0
- agno/models/vllm/__init__.py +3 -0
- agno/models/vllm/vllm.py +83 -0
- agno/models/xai/__init__.py +2 -0
- agno/models/xai/xai.py +111 -7
- agno/os/__init__.py +3 -0
- agno/os/app.py +1027 -0
- agno/os/auth.py +244 -0
- agno/os/config.py +126 -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 +249 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/__init__.py +3 -0
- agno/os/interfaces/agui/agui.py +47 -0
- agno/os/interfaces/agui/router.py +147 -0
- agno/os/interfaces/agui/utils.py +574 -0
- agno/os/interfaces/base.py +25 -0
- agno/os/interfaces/slack/__init__.py +3 -0
- agno/os/interfaces/slack/router.py +148 -0
- agno/os/interfaces/slack/security.py +30 -0
- agno/os/interfaces/slack/slack.py +47 -0
- agno/os/interfaces/whatsapp/__init__.py +3 -0
- agno/os/interfaces/whatsapp/router.py +210 -0
- agno/os/interfaces/whatsapp/security.py +55 -0
- agno/os/interfaces/whatsapp/whatsapp.py +36 -0
- agno/os/mcp.py +293 -0
- agno/os/middleware/__init__.py +9 -0
- agno/os/middleware/jwt.py +797 -0
- agno/os/router.py +258 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +599 -0
- agno/os/routers/agents/schema.py +261 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +450 -0
- agno/os/routers/evals/schemas.py +174 -0
- agno/os/routers/evals/utils.py +231 -0
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/__init__.py +3 -0
- agno/os/routers/knowledge/knowledge.py +1008 -0
- agno/os/routers/knowledge/schemas.py +178 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +661 -0
- agno/os/routers/memory/schemas.py +88 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +190 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +997 -0
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +512 -0
- agno/os/routers/teams/schema.py +257 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +499 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +624 -0
- agno/os/routers/workflows/schema.py +75 -0
- agno/os/schema.py +534 -0
- agno/os/scopes.py +469 -0
- agno/{playground → os}/settings.py +7 -15
- agno/os/utils.py +973 -0
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +67 -0
- agno/reasoning/deepseek.py +63 -0
- agno/reasoning/default.py +97 -0
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +71 -0
- agno/reasoning/helpers.py +24 -1
- agno/reasoning/ollama.py +67 -0
- agno/reasoning/openai.py +86 -0
- agno/reasoning/step.py +2 -1
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +822 -0
- agno/run/base.py +247 -0
- agno/run/cancel.py +81 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +767 -0
- agno/run/workflow.py +708 -0
- agno/session/__init__.py +10 -0
- agno/session/agent.py +260 -0
- agno/session/summary.py +265 -0
- agno/session/team.py +342 -0
- agno/session/workflow.py +501 -0
- agno/table.py +10 -0
- agno/team/__init__.py +37 -0
- agno/team/team.py +9536 -0
- agno/tools/__init__.py +7 -0
- agno/tools/agentql.py +120 -0
- agno/tools/airflow.py +22 -12
- agno/tools/api.py +122 -0
- agno/tools/apify.py +276 -83
- agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
- agno/tools/aws_lambda.py +28 -7
- agno/tools/aws_ses.py +66 -0
- agno/tools/baidusearch.py +11 -4
- agno/tools/bitbucket.py +292 -0
- agno/tools/brandfetch.py +213 -0
- agno/tools/bravesearch.py +106 -0
- agno/tools/brightdata.py +367 -0
- agno/tools/browserbase.py +209 -0
- agno/tools/calcom.py +32 -23
- agno/tools/calculator.py +24 -37
- agno/tools/cartesia.py +187 -0
- agno/tools/{clickup_tool.py → clickup.py} +17 -28
- agno/tools/confluence.py +91 -26
- agno/tools/crawl4ai.py +139 -43
- agno/tools/csv_toolkit.py +28 -22
- agno/tools/dalle.py +36 -22
- agno/tools/daytona.py +475 -0
- agno/tools/decorator.py +169 -14
- agno/tools/desi_vocal.py +23 -11
- agno/tools/discord.py +32 -29
- agno/tools/docker.py +716 -0
- agno/tools/duckdb.py +76 -81
- agno/tools/duckduckgo.py +43 -40
- agno/tools/e2b.py +703 -0
- agno/tools/eleven_labs.py +65 -54
- agno/tools/email.py +13 -5
- agno/tools/evm.py +129 -0
- agno/tools/exa.py +324 -42
- agno/tools/fal.py +39 -35
- agno/tools/file.py +196 -30
- agno/tools/file_generation.py +356 -0
- agno/tools/financial_datasets.py +288 -0
- agno/tools/firecrawl.py +108 -33
- agno/tools/function.py +960 -122
- agno/tools/giphy.py +34 -12
- agno/tools/github.py +1294 -97
- agno/tools/gmail.py +922 -0
- agno/tools/google_bigquery.py +117 -0
- agno/tools/google_drive.py +271 -0
- agno/tools/google_maps.py +253 -0
- agno/tools/googlecalendar.py +607 -107
- agno/tools/googlesheets.py +377 -0
- agno/tools/hackernews.py +20 -12
- agno/tools/jina.py +24 -14
- agno/tools/jira.py +48 -19
- agno/tools/knowledge.py +218 -0
- agno/tools/linear.py +82 -43
- agno/tools/linkup.py +58 -0
- agno/tools/local_file_system.py +15 -7
- agno/tools/lumalab.py +41 -26
- 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 +193 -0
- agno/tools/memory.py +419 -0
- agno/tools/mlx_transcribe.py +11 -9
- agno/tools/models/azure_openai.py +190 -0
- agno/tools/models/gemini.py +203 -0
- agno/tools/models/groq.py +158 -0
- agno/tools/models/morph.py +186 -0
- agno/tools/models/nebius.py +124 -0
- agno/tools/models_labs.py +163 -82
- agno/tools/moviepy_video.py +18 -13
- agno/tools/nano_banana.py +151 -0
- agno/tools/neo4j.py +134 -0
- agno/tools/newspaper.py +15 -4
- agno/tools/newspaper4k.py +19 -6
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +181 -17
- agno/tools/openbb.py +27 -20
- agno/tools/opencv.py +321 -0
- agno/tools/openweather.py +233 -0
- agno/tools/oxylabs.py +385 -0
- agno/tools/pandas.py +25 -15
- agno/tools/parallel.py +314 -0
- agno/tools/postgres.py +238 -185
- agno/tools/pubmed.py +125 -13
- agno/tools/python.py +48 -35
- agno/tools/reasoning.py +283 -0
- agno/tools/reddit.py +207 -29
- agno/tools/redshift.py +406 -0
- agno/tools/replicate.py +69 -26
- agno/tools/resend.py +11 -6
- agno/tools/scrapegraph.py +179 -19
- agno/tools/searxng.py +23 -31
- agno/tools/serpapi.py +15 -10
- agno/tools/serper.py +255 -0
- agno/tools/shell.py +23 -12
- agno/tools/shopify.py +1519 -0
- agno/tools/slack.py +56 -14
- agno/tools/sleep.py +8 -6
- agno/tools/spider.py +35 -11
- agno/tools/spotify.py +919 -0
- agno/tools/sql.py +34 -19
- agno/tools/tavily.py +158 -8
- agno/tools/telegram.py +18 -8
- agno/tools/todoist.py +218 -0
- agno/tools/toolkit.py +134 -9
- agno/tools/trafilatura.py +388 -0
- agno/tools/trello.py +25 -28
- agno/tools/twilio.py +18 -9
- agno/tools/user_control_flow.py +78 -0
- agno/tools/valyu.py +228 -0
- agno/tools/visualization.py +467 -0
- agno/tools/webbrowser.py +28 -0
- agno/tools/webex.py +76 -0
- agno/tools/website.py +23 -19
- agno/tools/webtools.py +45 -0
- agno/tools/whatsapp.py +286 -0
- agno/tools/wikipedia.py +28 -19
- agno/tools/workflow.py +285 -0
- agno/tools/{twitter.py → x.py} +142 -46
- agno/tools/yfinance.py +41 -39
- agno/tools/youtube.py +34 -17
- agno/tools/zendesk.py +15 -5
- agno/tools/zep.py +454 -0
- agno/tools/zoom.py +86 -37
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +157 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +111 -0
- agno/utils/agent.py +938 -0
- agno/utils/audio.py +37 -1
- agno/utils/certs.py +27 -0
- agno/utils/code_execution.py +11 -0
- agno/utils/common.py +103 -20
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +700 -0
- agno/utils/functions.py +107 -37
- agno/utils/gemini.py +426 -0
- agno/utils/hooks.py +171 -0
- agno/utils/http.py +185 -0
- agno/utils/json_schema.py +159 -37
- agno/utils/knowledge.py +36 -0
- agno/utils/location.py +19 -0
- agno/utils/log.py +221 -8
- agno/utils/mcp.py +214 -0
- agno/utils/media.py +335 -14
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +77 -2
- agno/utils/models/ai_foundry.py +50 -0
- agno/utils/models/claude.py +373 -0
- agno/utils/models/cohere.py +94 -0
- agno/utils/models/llama.py +85 -0
- agno/utils/models/mistral.py +100 -0
- agno/utils/models/openai_responses.py +140 -0
- agno/utils/models/schema_utils.py +153 -0
- agno/utils/models/watsonx.py +41 -0
- agno/utils/openai.py +257 -0
- agno/utils/pickle.py +1 -1
- agno/utils/pprint.py +124 -8
- agno/utils/print_response/agent.py +930 -0
- agno/utils/print_response/team.py +1914 -0
- agno/utils/print_response/workflow.py +1668 -0
- agno/utils/prompts.py +111 -0
- agno/utils/reasoning.py +108 -0
- agno/utils/response.py +163 -0
- agno/utils/serialize.py +32 -0
- agno/utils/shell.py +4 -4
- agno/utils/streamlit.py +487 -0
- agno/utils/string.py +204 -51
- agno/utils/team.py +139 -0
- agno/utils/timer.py +9 -2
- agno/utils/tokens.py +657 -0
- agno/utils/tools.py +19 -1
- agno/utils/whatsapp.py +305 -0
- agno/utils/yaml_io.py +3 -3
- agno/vectordb/__init__.py +2 -0
- agno/vectordb/base.py +87 -9
- agno/vectordb/cassandra/__init__.py +5 -1
- agno/vectordb/cassandra/cassandra.py +383 -27
- agno/vectordb/chroma/__init__.py +4 -0
- agno/vectordb/chroma/chromadb.py +748 -83
- agno/vectordb/clickhouse/__init__.py +7 -1
- agno/vectordb/clickhouse/clickhousedb.py +554 -53
- agno/vectordb/couchbase/__init__.py +3 -0
- agno/vectordb/couchbase/couchbase.py +1446 -0
- agno/vectordb/lancedb/__init__.py +5 -0
- agno/vectordb/lancedb/lance_db.py +730 -98
- agno/vectordb/langchaindb/__init__.py +5 -0
- agno/vectordb/langchaindb/langchaindb.py +163 -0
- agno/vectordb/lightrag/__init__.py +5 -0
- agno/vectordb/lightrag/lightrag.py +388 -0
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +166 -0
- agno/vectordb/milvus/__init__.py +3 -0
- agno/vectordb/milvus/milvus.py +966 -78
- agno/vectordb/mongodb/__init__.py +9 -1
- agno/vectordb/mongodb/mongodb.py +1175 -172
- agno/vectordb/pgvector/__init__.py +8 -0
- agno/vectordb/pgvector/pgvector.py +599 -115
- agno/vectordb/pineconedb/__init__.py +5 -1
- agno/vectordb/pineconedb/pineconedb.py +406 -43
- agno/vectordb/qdrant/__init__.py +4 -0
- agno/vectordb/qdrant/qdrant.py +914 -61
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +682 -0
- agno/vectordb/singlestore/__init__.py +8 -1
- agno/vectordb/singlestore/singlestore.py +771 -0
- agno/vectordb/surrealdb/__init__.py +3 -0
- agno/vectordb/surrealdb/surrealdb.py +663 -0
- agno/vectordb/upstashdb/__init__.py +5 -0
- agno/vectordb/upstashdb/upstashdb.py +718 -0
- agno/vectordb/weaviate/__init__.py +8 -0
- agno/vectordb/weaviate/index.py +15 -0
- agno/vectordb/weaviate/weaviate.py +1009 -0
- agno/workflow/__init__.py +23 -1
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +759 -0
- agno/workflow/loop.py +756 -0
- agno/workflow/parallel.py +853 -0
- agno/workflow/router.py +723 -0
- agno/workflow/step.py +1564 -0
- agno/workflow/steps.py +613 -0
- agno/workflow/types.py +556 -0
- agno/workflow/workflow.py +4327 -514
- agno-2.3.13.dist-info/METADATA +639 -0
- agno-2.3.13.dist-info/RECORD +613 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
- agno-2.3.13.dist-info/licenses/LICENSE +201 -0
- agno/api/playground.py +0 -91
- agno/api/schemas/playground.py +0 -22
- agno/api/schemas/user.py +0 -22
- agno/api/schemas/workspace.py +0 -46
- agno/api/user.py +0 -160
- agno/api/workspace.py +0 -151
- agno/cli/auth_server.py +0 -118
- agno/cli/config.py +0 -275
- agno/cli/console.py +0 -88
- agno/cli/credentials.py +0 -23
- agno/cli/entrypoint.py +0 -571
- agno/cli/operator.py +0 -355
- agno/cli/settings.py +0 -85
- agno/cli/ws/ws_cli.py +0 -817
- agno/constants.py +0 -13
- agno/document/__init__.py +0 -1
- agno/document/chunking/semantic.py +0 -47
- agno/document/chunking/strategy.py +0 -31
- agno/document/reader/__init__.py +0 -1
- agno/document/reader/arxiv_reader.py +0 -41
- agno/document/reader/base.py +0 -22
- agno/document/reader/csv_reader.py +0 -84
- agno/document/reader/docx_reader.py +0 -46
- agno/document/reader/firecrawl_reader.py +0 -99
- agno/document/reader/json_reader.py +0 -43
- agno/document/reader/pdf_reader.py +0 -219
- agno/document/reader/s3/pdf_reader.py +0 -46
- agno/document/reader/s3/text_reader.py +0 -51
- agno/document/reader/text_reader.py +0 -41
- agno/document/reader/website_reader.py +0 -175
- agno/document/reader/youtube_reader.py +0 -50
- agno/embedder/__init__.py +0 -1
- agno/embedder/azure_openai.py +0 -86
- agno/embedder/cohere.py +0 -72
- agno/embedder/fastembed.py +0 -37
- agno/embedder/google.py +0 -73
- agno/embedder/huggingface.py +0 -54
- agno/embedder/mistral.py +0 -80
- agno/embedder/ollama.py +0 -57
- agno/embedder/openai.py +0 -74
- agno/embedder/sentence_transformer.py +0 -38
- agno/embedder/voyageai.py +0 -64
- agno/eval/perf.py +0 -201
- agno/file/__init__.py +0 -1
- agno/file/file.py +0 -16
- agno/file/local/csv.py +0 -32
- agno/file/local/txt.py +0 -19
- agno/infra/app.py +0 -240
- agno/infra/base.py +0 -144
- agno/infra/context.py +0 -20
- agno/infra/db_app.py +0 -52
- agno/infra/resource.py +0 -205
- agno/infra/resources.py +0 -55
- agno/knowledge/agent.py +0 -230
- agno/knowledge/arxiv.py +0 -22
- agno/knowledge/combined.py +0 -22
- agno/knowledge/csv.py +0 -28
- agno/knowledge/csv_url.py +0 -19
- agno/knowledge/document.py +0 -20
- agno/knowledge/docx.py +0 -30
- agno/knowledge/json.py +0 -28
- agno/knowledge/langchain.py +0 -71
- agno/knowledge/llamaindex.py +0 -66
- agno/knowledge/pdf.py +0 -28
- agno/knowledge/pdf_url.py +0 -26
- agno/knowledge/s3/base.py +0 -60
- agno/knowledge/s3/pdf.py +0 -21
- agno/knowledge/s3/text.py +0 -23
- agno/knowledge/text.py +0 -30
- agno/knowledge/website.py +0 -88
- agno/knowledge/wikipedia.py +0 -31
- agno/knowledge/youtube.py +0 -22
- agno/memory/agent.py +0 -392
- agno/memory/classifier.py +0 -104
- agno/memory/db/__init__.py +0 -1
- agno/memory/db/base.py +0 -42
- agno/memory/db/mongodb.py +0 -189
- agno/memory/db/postgres.py +0 -203
- agno/memory/db/sqlite.py +0 -193
- agno/memory/memory.py +0 -15
- agno/memory/row.py +0 -36
- agno/memory/summarizer.py +0 -192
- agno/memory/summary.py +0 -19
- agno/memory/workflow.py +0 -38
- agno/models/google/gemini_openai.py +0 -26
- agno/models/ollama/hermes.py +0 -221
- agno/models/ollama/tools.py +0 -362
- agno/models/vertexai/gemini.py +0 -595
- agno/playground/__init__.py +0 -3
- agno/playground/async_router.py +0 -421
- agno/playground/deploy.py +0 -249
- agno/playground/operator.py +0 -92
- agno/playground/playground.py +0 -91
- agno/playground/schemas.py +0 -76
- agno/playground/serve.py +0 -55
- agno/playground/sync_router.py +0 -405
- agno/reasoning/agent.py +0 -68
- agno/run/response.py +0 -112
- agno/storage/agent/__init__.py +0 -0
- agno/storage/agent/base.py +0 -38
- agno/storage/agent/dynamodb.py +0 -350
- agno/storage/agent/json.py +0 -92
- agno/storage/agent/mongodb.py +0 -228
- agno/storage/agent/postgres.py +0 -367
- agno/storage/agent/session.py +0 -79
- agno/storage/agent/singlestore.py +0 -303
- agno/storage/agent/sqlite.py +0 -357
- agno/storage/agent/yaml.py +0 -93
- agno/storage/workflow/__init__.py +0 -0
- agno/storage/workflow/base.py +0 -40
- agno/storage/workflow/mongodb.py +0 -233
- agno/storage/workflow/postgres.py +0 -366
- agno/storage/workflow/session.py +0 -60
- agno/storage/workflow/sqlite.py +0 -359
- agno/tools/googlesearch.py +0 -88
- agno/utils/defaults.py +0 -57
- agno/utils/filesystem.py +0 -39
- agno/utils/git.py +0 -52
- agno/utils/json_io.py +0 -30
- agno/utils/load_env.py +0 -19
- agno/utils/py_io.py +0 -19
- agno/utils/pyproject.py +0 -18
- agno/utils/resource_filter.py +0 -31
- agno/vectordb/singlestore/s2vectordb.py +0 -390
- agno/vectordb/singlestore/s2vectordb2.py +0 -355
- agno/workspace/__init__.py +0 -0
- agno/workspace/config.py +0 -325
- agno/workspace/enums.py +0 -6
- agno/workspace/helpers.py +0 -48
- agno/workspace/operator.py +0 -758
- agno/workspace/settings.py +0 -63
- agno-0.1.2.dist-info/LICENSE +0 -375
- agno-0.1.2.dist-info/METADATA +0 -502
- agno-0.1.2.dist-info/RECORD +0 -352
- agno-0.1.2.dist-info/entry_points.txt +0 -3
- /agno/{cli → db/migrations}/__init__.py +0 -0
- /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
- /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
- /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
- /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
- /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
- /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
- /agno/{reranker → utils/models}/__init__.py +0 -0
- /agno/{storage → utils/print_response}/__init__.py +0 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
import asyncio
|
|
2
|
+
from typing import Any, Dict, Iterable, List, Optional, Union
|
|
2
3
|
|
|
3
|
-
from agno.
|
|
4
|
-
from agno.
|
|
5
|
-
from agno.
|
|
4
|
+
from agno.filters import FilterExpr
|
|
5
|
+
from agno.knowledge.document import Document
|
|
6
|
+
from agno.knowledge.embedder import Embedder
|
|
7
|
+
from agno.utils.log import log_debug, log_error, log_info, log_warning
|
|
6
8
|
from agno.vectordb.base import VectorDb
|
|
7
9
|
from agno.vectordb.cassandra.index import AgnoMetadataVectorCassandraTable
|
|
8
10
|
|
|
9
11
|
|
|
10
|
-
class
|
|
12
|
+
class Cassandra(VectorDb):
|
|
11
13
|
def __init__(
|
|
12
14
|
self,
|
|
13
15
|
table_name: str,
|
|
14
16
|
keyspace: str,
|
|
15
17
|
embedder: Optional[Embedder] = None,
|
|
16
18
|
session=None,
|
|
19
|
+
name: Optional[str] = None,
|
|
20
|
+
description: Optional[str] = None,
|
|
17
21
|
) -> None:
|
|
18
22
|
if not table_name:
|
|
19
23
|
raise ValueError("Table name must be provided.")
|
|
@@ -25,9 +29,13 @@ class CassandraDb(VectorDb):
|
|
|
25
29
|
raise ValueError("Keyspace must be provided")
|
|
26
30
|
|
|
27
31
|
if embedder is None:
|
|
28
|
-
from agno.embedder.openai import OpenAIEmbedder
|
|
32
|
+
from agno.knowledge.embedder.openai import OpenAIEmbedder
|
|
29
33
|
|
|
30
34
|
embedder = OpenAIEmbedder()
|
|
35
|
+
log_info("Embedder not provided, using OpenAIEmbedder as default.")
|
|
36
|
+
# Initialize base class with name and description
|
|
37
|
+
super().__init__(name=name, description=description)
|
|
38
|
+
|
|
31
39
|
self.table_name: str = table_name
|
|
32
40
|
self.embedder: Embedder = embedder
|
|
33
41
|
self.session = session
|
|
@@ -46,42 +54,130 @@ class CassandraDb(VectorDb):
|
|
|
46
54
|
def create(self) -> None:
|
|
47
55
|
"""Create the table in Cassandra for storing vectors and metadata."""
|
|
48
56
|
if not self.exists():
|
|
49
|
-
|
|
57
|
+
log_debug(f"Cassandra VectorDB : Creating table {self.table_name}")
|
|
50
58
|
self.initialize_table()
|
|
51
59
|
|
|
60
|
+
async def async_create(self) -> None:
|
|
61
|
+
"""Create the table asynchronously by running in a thread."""
|
|
62
|
+
await asyncio.to_thread(self.create)
|
|
63
|
+
|
|
52
64
|
def _row_to_document(self, row: Dict[str, Any]) -> Document:
|
|
65
|
+
metadata = row["metadata"]
|
|
53
66
|
return Document(
|
|
54
67
|
id=row["row_id"],
|
|
55
68
|
content=row["body_blob"],
|
|
56
|
-
meta_data=
|
|
69
|
+
meta_data=metadata,
|
|
57
70
|
embedding=row["vector"],
|
|
58
71
|
name=row["document_name"],
|
|
72
|
+
content_id=metadata.get("content_id"),
|
|
59
73
|
)
|
|
60
74
|
|
|
61
|
-
def doc_exists(self, document: Document) -> bool:
|
|
62
|
-
"""Check if a document exists by ID."""
|
|
63
|
-
query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
|
|
64
|
-
result = self.session.execute(query, (document.id,))
|
|
65
|
-
return result[0].count > 0
|
|
66
|
-
|
|
67
75
|
def name_exists(self, name: str) -> bool:
|
|
68
76
|
"""Check if a document exists by name."""
|
|
69
|
-
query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE document_name = %s"
|
|
77
|
+
query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE document_name = %s ALLOW FILTERING"
|
|
70
78
|
result = self.session.execute(query, (name,))
|
|
71
|
-
return result[0]
|
|
79
|
+
return result.one()[0] > 0
|
|
80
|
+
|
|
81
|
+
async def async_name_exists(self, name: str) -> bool:
|
|
82
|
+
"""Check if a document with given name exists asynchronously."""
|
|
83
|
+
return await asyncio.to_thread(self.name_exists, name)
|
|
72
84
|
|
|
73
85
|
def id_exists(self, id: str) -> bool:
|
|
74
86
|
"""Check if a document exists by ID."""
|
|
75
|
-
query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
|
|
87
|
+
query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE row_id = %s ALLOW FILTERING"
|
|
76
88
|
result = self.session.execute(query, (id,))
|
|
77
|
-
return result[0]
|
|
89
|
+
return result.one()[0] > 0
|
|
90
|
+
|
|
91
|
+
def content_hash_exists(self, content_hash: str) -> bool:
|
|
92
|
+
"""Check if a document exists by content hash."""
|
|
93
|
+
query = f"SELECT COUNT(*) FROM {self.keyspace}.{self.table_name} WHERE metadata_s['content_hash'] = %s ALLOW FILTERING"
|
|
94
|
+
result = self.session.execute(query, (content_hash,))
|
|
95
|
+
return result.one()[0] > 0
|
|
78
96
|
|
|
79
|
-
def insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
80
|
-
|
|
97
|
+
def insert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
98
|
+
log_info(f"Cassandra VectorDB : Inserting Documents to the table {self.table_name}")
|
|
81
99
|
futures = []
|
|
82
100
|
for doc in documents:
|
|
83
101
|
doc.embed(embedder=self.embedder)
|
|
84
102
|
metadata = {key: str(value) for key, value in doc.meta_data.items()}
|
|
103
|
+
metadata.update(filters or {})
|
|
104
|
+
metadata["content_id"] = doc.content_id or ""
|
|
105
|
+
metadata["content_hash"] = content_hash
|
|
106
|
+
futures.append(
|
|
107
|
+
self.table.put_async(
|
|
108
|
+
row_id=doc.id,
|
|
109
|
+
vector=doc.embedding,
|
|
110
|
+
metadata=metadata or {},
|
|
111
|
+
body_blob=doc.content,
|
|
112
|
+
document_name=doc.name,
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
for f in futures:
|
|
117
|
+
f.result()
|
|
118
|
+
|
|
119
|
+
async def async_insert(
|
|
120
|
+
self,
|
|
121
|
+
content_hash: str,
|
|
122
|
+
documents: List[Document],
|
|
123
|
+
filters: Optional[Dict[str, Any]] = None,
|
|
124
|
+
) -> None:
|
|
125
|
+
"""Insert documents asynchronously by running in a thread."""
|
|
126
|
+
log_info(f"Cassandra VectorDB : Inserting Documents to the table {self.table_name}")
|
|
127
|
+
|
|
128
|
+
if self.embedder.enable_batch and hasattr(self.embedder, "async_get_embeddings_batch_and_usage"):
|
|
129
|
+
# Use batch embedding when enabled and supported
|
|
130
|
+
try:
|
|
131
|
+
# Extract content from all documents
|
|
132
|
+
doc_contents = [doc.content for doc in documents]
|
|
133
|
+
|
|
134
|
+
# Get batch embeddings and usage
|
|
135
|
+
embeddings, usages = await self.embedder.async_get_embeddings_batch_and_usage(doc_contents)
|
|
136
|
+
|
|
137
|
+
# Process documents with pre-computed embeddings
|
|
138
|
+
for j, doc in enumerate(documents):
|
|
139
|
+
try:
|
|
140
|
+
if j < len(embeddings):
|
|
141
|
+
doc.embedding = embeddings[j]
|
|
142
|
+
doc.usage = usages[j] if j < len(usages) else None
|
|
143
|
+
except Exception as e:
|
|
144
|
+
log_error(f"Error assigning batch embedding to document '{doc.name}': {e}")
|
|
145
|
+
|
|
146
|
+
except Exception as e:
|
|
147
|
+
# Check if this is a rate limit error - don't fall back as it would make things worse
|
|
148
|
+
error_str = str(e).lower()
|
|
149
|
+
is_rate_limit = any(
|
|
150
|
+
phrase in error_str
|
|
151
|
+
for phrase in ["rate limit", "too many requests", "429", "trial key", "api calls / minute"]
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
if is_rate_limit:
|
|
155
|
+
log_error(f"Rate limit detected during batch embedding. {e}")
|
|
156
|
+
raise e
|
|
157
|
+
else:
|
|
158
|
+
log_error(f"Async batch embedding failed, falling back to individual embeddings: {e}")
|
|
159
|
+
# Fall back to individual embedding
|
|
160
|
+
for doc in documents:
|
|
161
|
+
try:
|
|
162
|
+
embed_tasks = [doc.async_embed(embedder=self.embedder)]
|
|
163
|
+
await asyncio.gather(*embed_tasks, return_exceptions=True)
|
|
164
|
+
except Exception as e:
|
|
165
|
+
log_error(f"Error processing document '{doc.name}': {e}")
|
|
166
|
+
else:
|
|
167
|
+
# Use individual embedding (original behavior)
|
|
168
|
+
for doc in documents:
|
|
169
|
+
try:
|
|
170
|
+
embed_tasks = [doc.async_embed(embedder=self.embedder)]
|
|
171
|
+
await asyncio.gather(*embed_tasks, return_exceptions=True)
|
|
172
|
+
except Exception as e:
|
|
173
|
+
log_error(f"Error processing document '{doc.name}': {e}")
|
|
174
|
+
|
|
175
|
+
futures = []
|
|
176
|
+
for doc in documents:
|
|
177
|
+
metadata = {key: str(value) for key, value in doc.meta_data.items()}
|
|
178
|
+
metadata.update(filters or {})
|
|
179
|
+
metadata["content_id"] = doc.content_id or ""
|
|
180
|
+
metadata["content_hash"] = content_hash
|
|
85
181
|
futures.append(
|
|
86
182
|
self.table.put_async(
|
|
87
183
|
row_id=doc.id,
|
|
@@ -95,22 +191,44 @@ class CassandraDb(VectorDb):
|
|
|
95
191
|
for f in futures:
|
|
96
192
|
f.result()
|
|
97
193
|
|
|
98
|
-
def upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
194
|
+
def upsert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
99
195
|
"""Insert or update documents based on primary key."""
|
|
100
|
-
self.
|
|
196
|
+
if self.content_hash_exists(content_hash):
|
|
197
|
+
self.delete_by_content_hash(content_hash)
|
|
198
|
+
self.insert(content_hash, documents, filters)
|
|
199
|
+
|
|
200
|
+
async def async_upsert(
|
|
201
|
+
self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
|
|
202
|
+
) -> None:
|
|
203
|
+
"""Upsert documents asynchronously by running in a thread."""
|
|
204
|
+
if self.content_hash_exists(content_hash):
|
|
205
|
+
self.delete_by_content_hash(content_hash)
|
|
206
|
+
await self.async_insert(content_hash, documents, filters)
|
|
101
207
|
|
|
102
|
-
def search(
|
|
208
|
+
def search(
|
|
209
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
210
|
+
) -> List[Document]:
|
|
103
211
|
"""Keyword-based search on document metadata."""
|
|
104
|
-
|
|
212
|
+
log_debug(f"Cassandra VectorDB : Performing Vector Search on {self.table_name} with query {query}")
|
|
213
|
+
if filters is not None:
|
|
214
|
+
log_warning("Filters are not yet supported in Cassandra. No filters will be applied.")
|
|
105
215
|
return self.vector_search(query=query, limit=limit)
|
|
106
216
|
|
|
217
|
+
async def async_search(
|
|
218
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
219
|
+
) -> List[Document]:
|
|
220
|
+
"""Search asynchronously by running in a thread."""
|
|
221
|
+
return await asyncio.to_thread(self.search, query, limit, filters)
|
|
222
|
+
|
|
107
223
|
def _search_to_documents(
|
|
108
224
|
self,
|
|
109
225
|
hits: Iterable[Dict[str, Any]],
|
|
110
226
|
) -> List[Document]:
|
|
111
227
|
return [self._row_to_document(row=hit) for hit in hits]
|
|
112
228
|
|
|
113
|
-
def vector_search(
|
|
229
|
+
def vector_search(
|
|
230
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
231
|
+
) -> List[Document]:
|
|
114
232
|
"""Vector similarity search implementation."""
|
|
115
233
|
query_embedding = self.embedder.get_embedding(query)
|
|
116
234
|
hits = list(
|
|
@@ -125,10 +243,14 @@ class CassandraDb(VectorDb):
|
|
|
125
243
|
|
|
126
244
|
def drop(self) -> None:
|
|
127
245
|
"""Drop the vector table in Cassandra."""
|
|
128
|
-
|
|
246
|
+
log_debug(f"Cassandra VectorDB : Dropping Table {self.table_name}")
|
|
129
247
|
drop_table_query = f"DROP TABLE IF EXISTS {self.keyspace}.{self.table_name}"
|
|
130
248
|
self.session.execute(drop_table_query)
|
|
131
249
|
|
|
250
|
+
async def async_drop(self) -> None:
|
|
251
|
+
"""Drop the table asynchronously by running in a thread."""
|
|
252
|
+
await asyncio.to_thread(self.drop)
|
|
253
|
+
|
|
132
254
|
def exists(self) -> bool:
|
|
133
255
|
"""Check if the table exists in Cassandra."""
|
|
134
256
|
check_table_query = """
|
|
@@ -138,8 +260,242 @@ class CassandraDb(VectorDb):
|
|
|
138
260
|
result = self.session.execute(check_table_query, (self.keyspace, self.table_name))
|
|
139
261
|
return bool(result.one())
|
|
140
262
|
|
|
263
|
+
async def async_exists(self) -> bool:
|
|
264
|
+
"""Check if table exists asynchronously by running in a thread."""
|
|
265
|
+
return await asyncio.to_thread(self.exists)
|
|
266
|
+
|
|
141
267
|
def delete(self) -> bool:
|
|
142
268
|
"""Delete all documents in the table."""
|
|
143
|
-
|
|
269
|
+
log_debug(f"Cassandra VectorDB : Clearing the table {self.table_name}")
|
|
144
270
|
self.table.clear()
|
|
145
271
|
return True
|
|
272
|
+
|
|
273
|
+
def delete_by_id(self, id: str) -> bool:
|
|
274
|
+
"""
|
|
275
|
+
Delete a document by its ID.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
id (str): The document ID to delete
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
bool: True if document was deleted, False otherwise
|
|
282
|
+
"""
|
|
283
|
+
try:
|
|
284
|
+
log_debug(f"Cassandra VectorDB : Deleting document with ID {id}")
|
|
285
|
+
# Check if document exists before deletion
|
|
286
|
+
if not self.id_exists(id):
|
|
287
|
+
return False
|
|
288
|
+
|
|
289
|
+
query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
|
|
290
|
+
self.session.execute(query, (id,))
|
|
291
|
+
return True
|
|
292
|
+
except Exception as e:
|
|
293
|
+
log_info(f"Error deleting document with ID {id}: {e}")
|
|
294
|
+
return False
|
|
295
|
+
|
|
296
|
+
def delete_by_name(self, name: str) -> bool:
|
|
297
|
+
"""
|
|
298
|
+
Delete documents by name.
|
|
299
|
+
|
|
300
|
+
Args:
|
|
301
|
+
name (str): The document name to delete
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
bool: True if documents were deleted, False otherwise
|
|
305
|
+
"""
|
|
306
|
+
try:
|
|
307
|
+
log_debug(f"Cassandra VectorDB : Deleting documents with name {name}")
|
|
308
|
+
# Check if document exists before deletion
|
|
309
|
+
if not self.name_exists(name):
|
|
310
|
+
return False
|
|
311
|
+
|
|
312
|
+
# Query to find documents with matching name
|
|
313
|
+
query = f"SELECT row_id, document_name FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
|
|
314
|
+
result = self.session.execute(query)
|
|
315
|
+
|
|
316
|
+
deleted_count = 0
|
|
317
|
+
for row in result:
|
|
318
|
+
# Check if the row's document_name matches our criteria
|
|
319
|
+
# Use attribute access for Row objects
|
|
320
|
+
row_name = getattr(row, "document_name", None)
|
|
321
|
+
if row_name == name:
|
|
322
|
+
# Delete this specific document
|
|
323
|
+
delete_query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
|
|
324
|
+
self.session.execute(delete_query, (getattr(row, "row_id"),))
|
|
325
|
+
deleted_count += 1
|
|
326
|
+
|
|
327
|
+
return deleted_count > 0
|
|
328
|
+
except Exception as e:
|
|
329
|
+
log_info(f"Error deleting documents with name {name}: {e}")
|
|
330
|
+
return False
|
|
331
|
+
|
|
332
|
+
def delete_by_metadata(self, metadata: Dict[str, Any]) -> bool:
|
|
333
|
+
"""
|
|
334
|
+
Delete documents by metadata.
|
|
335
|
+
|
|
336
|
+
Args:
|
|
337
|
+
metadata (Dict[str, Any]): The metadata to match for deletion
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
bool: True if documents were deleted, False otherwise
|
|
341
|
+
"""
|
|
342
|
+
try:
|
|
343
|
+
log_debug(f"Cassandra VectorDB : Deleting documents with metadata {metadata}")
|
|
344
|
+
# For metadata deletion, we need to query first to find matching documents
|
|
345
|
+
# Then delete them by their IDs
|
|
346
|
+
query = f"SELECT row_id, metadata_s FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
|
|
347
|
+
result = self.session.execute(query)
|
|
348
|
+
|
|
349
|
+
deleted_count = 0
|
|
350
|
+
for row in result:
|
|
351
|
+
# Check if the row's metadata matches our criteria
|
|
352
|
+
# Use attribute access for Row objects
|
|
353
|
+
row_metadata = getattr(row, "metadata_s", {})
|
|
354
|
+
if self._metadata_matches(row_metadata, metadata):
|
|
355
|
+
# Delete this specific document
|
|
356
|
+
delete_query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
|
|
357
|
+
self.session.execute(delete_query, (getattr(row, "row_id"),))
|
|
358
|
+
deleted_count += 1
|
|
359
|
+
|
|
360
|
+
return deleted_count > 0
|
|
361
|
+
except Exception as e:
|
|
362
|
+
log_debug(f"Error deleting documents with metadata {metadata}: {e}")
|
|
363
|
+
return False
|
|
364
|
+
|
|
365
|
+
def delete_by_content_id(self, content_id: str) -> bool:
|
|
366
|
+
"""
|
|
367
|
+
Delete documents by content ID.
|
|
368
|
+
|
|
369
|
+
Args:
|
|
370
|
+
content_id (str): The content ID to delete
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
bool: True if documents were deleted, False otherwise
|
|
374
|
+
"""
|
|
375
|
+
try:
|
|
376
|
+
log_debug(f"Cassandra VectorDB : Deleting documents with content_id {content_id}")
|
|
377
|
+
# Query to find documents with matching content_id in metadata
|
|
378
|
+
query = f"SELECT row_id, metadata_s FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
|
|
379
|
+
result = self.session.execute(query)
|
|
380
|
+
deleted_count = 0
|
|
381
|
+
for row in result:
|
|
382
|
+
# Check if the row's metadata contains the content_id
|
|
383
|
+
# Use attribute access for Row objects
|
|
384
|
+
row_metadata = getattr(row, "metadata_s", {})
|
|
385
|
+
if row_metadata.get("content_id") == content_id:
|
|
386
|
+
# Delete this specific document
|
|
387
|
+
delete_query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
|
|
388
|
+
self.session.execute(delete_query, (getattr(row, "row_id"),))
|
|
389
|
+
deleted_count += 1
|
|
390
|
+
|
|
391
|
+
return deleted_count > 0
|
|
392
|
+
except Exception as e:
|
|
393
|
+
log_info(f"Error deleting documents with content_id {content_id}: {e}")
|
|
394
|
+
return False
|
|
395
|
+
|
|
396
|
+
def delete_by_content_hash(self, content_hash: str) -> bool:
|
|
397
|
+
"""
|
|
398
|
+
Delete documents by content hash.
|
|
399
|
+
|
|
400
|
+
Args:
|
|
401
|
+
content_hash (str): The content hash to delete
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
bool: True if documents were deleted, False otherwise
|
|
405
|
+
"""
|
|
406
|
+
try:
|
|
407
|
+
log_debug(f"Cassandra VectorDB : Deleting documents with content_hash {content_hash}")
|
|
408
|
+
# Query to find documents with matching content_hash in metadata
|
|
409
|
+
query = f"SELECT row_id, metadata_s FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
|
|
410
|
+
result = self.session.execute(query)
|
|
411
|
+
deleted_count = 0
|
|
412
|
+
for row in result:
|
|
413
|
+
# Check if the row's metadata contains the content_hash
|
|
414
|
+
# Use attribute access for Row objects
|
|
415
|
+
row_metadata = getattr(row, "metadata_s", {})
|
|
416
|
+
if row_metadata.get("content_hash") == content_hash:
|
|
417
|
+
# Delete this specific document
|
|
418
|
+
delete_query = f"DELETE FROM {self.keyspace}.{self.table_name} WHERE row_id = %s"
|
|
419
|
+
self.session.execute(delete_query, (getattr(row, "row_id"),))
|
|
420
|
+
deleted_count += 1
|
|
421
|
+
|
|
422
|
+
return deleted_count > 0
|
|
423
|
+
except Exception as e:
|
|
424
|
+
log_info(f"Error deleting documents with content_hash {content_hash}: {e}")
|
|
425
|
+
return False
|
|
426
|
+
|
|
427
|
+
def _metadata_matches(self, row_metadata: Dict[str, Any], target_metadata: Dict[str, Any]) -> bool:
|
|
428
|
+
"""
|
|
429
|
+
Check if row metadata matches target metadata criteria.
|
|
430
|
+
|
|
431
|
+
Args:
|
|
432
|
+
row_metadata (Dict[str, Any]): The metadata from the database row
|
|
433
|
+
target_metadata (Dict[str, Any]): The target metadata to match against
|
|
434
|
+
|
|
435
|
+
Returns:
|
|
436
|
+
bool: True if metadata matches, False otherwise
|
|
437
|
+
"""
|
|
438
|
+
try:
|
|
439
|
+
for key, value in target_metadata.items():
|
|
440
|
+
if key not in row_metadata:
|
|
441
|
+
return False
|
|
442
|
+
|
|
443
|
+
# Handle boolean values specially
|
|
444
|
+
if isinstance(value, bool):
|
|
445
|
+
if row_metadata[key] != value:
|
|
446
|
+
return False
|
|
447
|
+
else:
|
|
448
|
+
# For non-boolean values, convert to string for comparison
|
|
449
|
+
if row_metadata[key] != str(value):
|
|
450
|
+
return False
|
|
451
|
+
return True
|
|
452
|
+
except Exception:
|
|
453
|
+
return False
|
|
454
|
+
|
|
455
|
+
def update_metadata(self, content_id: str, metadata: Dict[str, Any]) -> None:
|
|
456
|
+
"""
|
|
457
|
+
Update the metadata for a document.
|
|
458
|
+
|
|
459
|
+
Args:
|
|
460
|
+
content_id (str): The content ID to update
|
|
461
|
+
metadata (Dict[str, Any]): The metadata to update
|
|
462
|
+
"""
|
|
463
|
+
try:
|
|
464
|
+
log_debug(f"Cassandra VectorDB : Updating metadata for content_id {content_id}")
|
|
465
|
+
|
|
466
|
+
# First, find all documents with the given content_id
|
|
467
|
+
query = f"SELECT row_id, metadata_s FROM {self.keyspace}.{self.table_name} ALLOW FILTERING"
|
|
468
|
+
result = self.session.execute(query)
|
|
469
|
+
|
|
470
|
+
updated_count = 0
|
|
471
|
+
for row in result:
|
|
472
|
+
row_metadata = getattr(row, "metadata_s", {})
|
|
473
|
+
if row_metadata.get("content_id") == content_id:
|
|
474
|
+
# Merge existing metadata with new metadata
|
|
475
|
+
updated_metadata = row_metadata.copy()
|
|
476
|
+
# Convert new metadata values to strings (Cassandra requirement)
|
|
477
|
+
string_metadata = {key: str(value) for key, value in metadata.items()}
|
|
478
|
+
updated_metadata.update(string_metadata)
|
|
479
|
+
|
|
480
|
+
# Update the document with merged metadata
|
|
481
|
+
row_id = getattr(row, "row_id")
|
|
482
|
+
update_query = f"""
|
|
483
|
+
UPDATE {self.keyspace}.{self.table_name}
|
|
484
|
+
SET metadata_s = %s
|
|
485
|
+
WHERE row_id = %s
|
|
486
|
+
"""
|
|
487
|
+
self.session.execute(update_query, (updated_metadata, row_id))
|
|
488
|
+
updated_count += 1
|
|
489
|
+
|
|
490
|
+
if updated_count == 0:
|
|
491
|
+
log_debug(f"No documents found with content_id {content_id}")
|
|
492
|
+
else:
|
|
493
|
+
log_debug(f"Updated metadata for {updated_count} documents with content_id {content_id}")
|
|
494
|
+
|
|
495
|
+
except Exception as e:
|
|
496
|
+
log_error(f"Error updating metadata for content_id {content_id}: {e}")
|
|
497
|
+
raise
|
|
498
|
+
|
|
499
|
+
def get_supported_search_types(self) -> List[str]:
|
|
500
|
+
"""Get the supported search types for this vector database."""
|
|
501
|
+
return [] # Cassandra doesn't use SearchType enum
|