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
|
@@ -0,0 +1,663 @@
|
|
|
1
|
+
from typing import Any, Dict, Final, List, Optional, Union
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
from surrealdb import (
|
|
5
|
+
AsyncHttpSurrealConnection,
|
|
6
|
+
AsyncWsSurrealConnection,
|
|
7
|
+
BlockingHttpSurrealConnection,
|
|
8
|
+
BlockingWsSurrealConnection,
|
|
9
|
+
)
|
|
10
|
+
except ImportError as e:
|
|
11
|
+
msg = "The `surrealdb` package is not installed. Please install it via `pip install surrealdb`."
|
|
12
|
+
raise ImportError(msg) from e
|
|
13
|
+
|
|
14
|
+
from agno.filters import FilterExpr
|
|
15
|
+
from agno.knowledge.document import Document
|
|
16
|
+
from agno.knowledge.embedder import Embedder
|
|
17
|
+
from agno.utils.log import log_debug, log_error, log_info, log_warning
|
|
18
|
+
from agno.vectordb.base import VectorDb
|
|
19
|
+
from agno.vectordb.distance import Distance
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SurrealDb(VectorDb):
|
|
23
|
+
"""SurrealDB Vector Database implementation supporting both sync and async operations."""
|
|
24
|
+
|
|
25
|
+
# SQL Query Constants
|
|
26
|
+
CREATE_TABLE_QUERY: Final[str] = """
|
|
27
|
+
DEFINE TABLE IF NOT EXISTS {collection} SCHEMAFUL;
|
|
28
|
+
DEFINE FIELD IF NOT EXISTS content ON {collection} TYPE string;
|
|
29
|
+
DEFINE FIELD IF NOT EXISTS embedding ON {collection} TYPE array<float>;
|
|
30
|
+
DEFINE FIELD IF NOT EXISTS meta_data ON {collection} FLEXIBLE TYPE object;
|
|
31
|
+
DEFINE INDEX IF NOT EXISTS vector_idx ON {collection} FIELDS embedding HNSW DIMENSION {dimensions} DIST {distance};
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
NAME_EXISTS_QUERY: Final[str] = """
|
|
35
|
+
SELECT * FROM {collection}
|
|
36
|
+
WHERE meta_data.name = $name
|
|
37
|
+
LIMIT 1
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
ID_EXISTS_QUERY: Final[str] = """
|
|
41
|
+
SELECT * FROM {collection}
|
|
42
|
+
WHERE id = $id
|
|
43
|
+
LIMIT 1
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
CONTENT_HASH_EXISTS_QUERY: Final[str] = """
|
|
47
|
+
SELECT * FROM {collection}
|
|
48
|
+
WHERE meta_data.content_hash = $content_hash
|
|
49
|
+
LIMIT 1
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
DELETE_BY_ID_QUERY: Final[str] = """
|
|
53
|
+
DELETE FROM {collection}
|
|
54
|
+
WHERE id = $id
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
DELETE_BY_NAME_QUERY: Final[str] = """
|
|
58
|
+
DELETE FROM {collection}
|
|
59
|
+
WHERE meta_data.name = $name
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
DELETE_BY_METADATA_QUERY: Final[str] = """
|
|
63
|
+
DELETE FROM {collection}
|
|
64
|
+
WHERE {conditions}
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
DELETE_BY_CONTENT_ID_QUERY: Final[str] = """
|
|
68
|
+
DELETE FROM {collection}
|
|
69
|
+
WHERE content_id = $content_id
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
UPSERT_QUERY: Final[str] = """
|
|
73
|
+
UPSERT {thing}
|
|
74
|
+
SET content = $content,
|
|
75
|
+
embedding = $embedding,
|
|
76
|
+
meta_data = $meta_data
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
SEARCH_QUERY: Final[str] = """
|
|
80
|
+
SELECT
|
|
81
|
+
content,
|
|
82
|
+
meta_data,
|
|
83
|
+
vector::distance::knn() as distance
|
|
84
|
+
FROM {collection}
|
|
85
|
+
WHERE embedding <|{limit}, {search_ef}|> $query_embedding
|
|
86
|
+
{filter_condition}
|
|
87
|
+
ORDER BY distance ASC
|
|
88
|
+
LIMIT {limit};
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
INFO_DB_QUERY: Final[str] = "INFO FOR DB;"
|
|
92
|
+
DROP_TABLE_QUERY: Final[str] = "REMOVE TABLE {collection}"
|
|
93
|
+
DELETE_ALL_QUERY: Final[str] = "DELETE {collection}"
|
|
94
|
+
|
|
95
|
+
def __init__(
|
|
96
|
+
self,
|
|
97
|
+
client: Optional[Union[BlockingWsSurrealConnection, BlockingHttpSurrealConnection]] = None,
|
|
98
|
+
async_client: Optional[Union[AsyncWsSurrealConnection, AsyncHttpSurrealConnection]] = None,
|
|
99
|
+
collection: str = "documents",
|
|
100
|
+
distance: Distance = Distance.cosine,
|
|
101
|
+
efc: int = 150,
|
|
102
|
+
m: int = 12,
|
|
103
|
+
search_ef: int = 40,
|
|
104
|
+
embedder: Optional[Embedder] = None,
|
|
105
|
+
name: Optional[str] = None,
|
|
106
|
+
description: Optional[str] = None,
|
|
107
|
+
id: Optional[str] = None,
|
|
108
|
+
):
|
|
109
|
+
"""Initialize SurrealDB connection.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
client: A blocking connection, either HTTP or WS
|
|
113
|
+
async_client: An async connection, either HTTP or WS (default: None)
|
|
114
|
+
collection: Collection name to store documents (default: documents)
|
|
115
|
+
distance: Distance metric to use (default: cosine)
|
|
116
|
+
efc: HNSW construction time/accuracy trade-off (default: 150)
|
|
117
|
+
m: HNSW max number of connections per element (default: 12)
|
|
118
|
+
search_ef: HNSW search time/accuracy trade-off (default: 40)
|
|
119
|
+
embedder: Embedder instance for creating embeddings (default: OpenAIEmbedder)
|
|
120
|
+
|
|
121
|
+
"""
|
|
122
|
+
# Dynamic ID generation based on unique identifiers
|
|
123
|
+
if id is None:
|
|
124
|
+
from agno.utils.string import generate_id
|
|
125
|
+
|
|
126
|
+
client_info = str(client) if client else str(async_client) if async_client else "default"
|
|
127
|
+
seed = f"{client_info}#{collection}"
|
|
128
|
+
id = generate_id(seed)
|
|
129
|
+
|
|
130
|
+
# Initialize base class with name, description, and generated ID
|
|
131
|
+
super().__init__(id=id, name=name, description=description)
|
|
132
|
+
|
|
133
|
+
# Embedder for embedding the document contents
|
|
134
|
+
if embedder is None:
|
|
135
|
+
from agno.knowledge.embedder.openai import OpenAIEmbedder
|
|
136
|
+
|
|
137
|
+
embedder = OpenAIEmbedder()
|
|
138
|
+
log_info("Embedder not provided, using OpenAIEmbedder as default.")
|
|
139
|
+
self.embedder: Embedder = embedder
|
|
140
|
+
self.dimensions = self.embedder.dimensions
|
|
141
|
+
self.collection = collection
|
|
142
|
+
# Convert Distance enum to SurrealDB distance type
|
|
143
|
+
self.distance = {Distance.cosine: "COSINE", Distance.l2: "EUCLIDEAN", Distance.max_inner_product: "DOT"}[
|
|
144
|
+
distance
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
self._client: Optional[Union[BlockingHttpSurrealConnection, BlockingWsSurrealConnection]] = client
|
|
148
|
+
self._async_client: Optional[Union[AsyncWsSurrealConnection, AsyncHttpSurrealConnection]] = async_client
|
|
149
|
+
|
|
150
|
+
if self._client is None and self._async_client is None:
|
|
151
|
+
msg = "Client and async client are not provided. Please provide one of them."
|
|
152
|
+
raise RuntimeError(msg)
|
|
153
|
+
|
|
154
|
+
# HNSW index parameters
|
|
155
|
+
self.efc = efc
|
|
156
|
+
self.m = m
|
|
157
|
+
self.search_ef = search_ef
|
|
158
|
+
|
|
159
|
+
@property
|
|
160
|
+
def async_client(self) -> Union[AsyncWsSurrealConnection, AsyncHttpSurrealConnection]:
|
|
161
|
+
"""Check if the async client is initialized.
|
|
162
|
+
|
|
163
|
+
Raises:
|
|
164
|
+
RuntimeError: If the async client is not initialized.
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
The async client.
|
|
168
|
+
|
|
169
|
+
"""
|
|
170
|
+
if self._async_client is None:
|
|
171
|
+
msg = "Async client is not initialized"
|
|
172
|
+
raise RuntimeError(msg)
|
|
173
|
+
return self._async_client
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def client(self) -> Union[BlockingHttpSurrealConnection, BlockingWsSurrealConnection]:
|
|
177
|
+
"""Check if the client is initialized.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
The client.
|
|
181
|
+
|
|
182
|
+
"""
|
|
183
|
+
if self._client is None:
|
|
184
|
+
msg = "Client is not initialized"
|
|
185
|
+
raise RuntimeError(msg)
|
|
186
|
+
return self._client
|
|
187
|
+
|
|
188
|
+
@staticmethod
|
|
189
|
+
def _build_filter_condition(filters: Optional[Dict[str, Any]] = None) -> str:
|
|
190
|
+
"""Build filter condition for queries.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
filters: A dictionary of filters to apply to the query.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
A string representing the filter condition.
|
|
197
|
+
|
|
198
|
+
"""
|
|
199
|
+
if not filters:
|
|
200
|
+
return ""
|
|
201
|
+
conditions = [f"meta_data.{key} = ${key}" for key in filters]
|
|
202
|
+
return "AND " + " AND ".join(conditions)
|
|
203
|
+
|
|
204
|
+
# Synchronous methods
|
|
205
|
+
def create(self) -> None:
|
|
206
|
+
"""Create the vector collection and index."""
|
|
207
|
+
if not self.exists():
|
|
208
|
+
log_debug(f"Creating collection: {self.collection}")
|
|
209
|
+
query = self.CREATE_TABLE_QUERY.format(
|
|
210
|
+
collection=self.collection,
|
|
211
|
+
distance=self.distance,
|
|
212
|
+
dimensions=self.dimensions,
|
|
213
|
+
efc=self.efc,
|
|
214
|
+
m=self.m,
|
|
215
|
+
)
|
|
216
|
+
self.client.query(query)
|
|
217
|
+
|
|
218
|
+
def name_exists(self, name: str) -> bool:
|
|
219
|
+
"""Check if a document exists by its name.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
name: The name of the document to check.
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
True if the document exists, False otherwise.
|
|
226
|
+
|
|
227
|
+
"""
|
|
228
|
+
log_debug(f"Checking if document exists: {name}")
|
|
229
|
+
result = self.client.query(self.NAME_EXISTS_QUERY.format(collection=self.collection), {"name": name})
|
|
230
|
+
return bool(self._extract_result(result))
|
|
231
|
+
|
|
232
|
+
def id_exists(self, id: str) -> bool:
|
|
233
|
+
"""Check if a document exists by its ID.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
id: The ID of the document to check.
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
True if the document exists, False otherwise.
|
|
240
|
+
|
|
241
|
+
"""
|
|
242
|
+
log_debug(f"Checking if document exists by ID: {id}")
|
|
243
|
+
result = self.client.query(self.ID_EXISTS_QUERY.format(collection=self.collection), {"id": id})
|
|
244
|
+
return bool(self._extract_result(result))
|
|
245
|
+
|
|
246
|
+
def content_hash_exists(self, content_hash: str) -> bool:
|
|
247
|
+
"""Check if a document exists by its content hash.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
content_hash: The content hash of the document to check.
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
True if the document exists, False otherwise.
|
|
254
|
+
|
|
255
|
+
"""
|
|
256
|
+
log_debug(f"Checking if document exists by content hash: {content_hash}")
|
|
257
|
+
result = self.client.query(
|
|
258
|
+
self.CONTENT_HASH_EXISTS_QUERY.format(collection=self.collection), {"content_hash": content_hash}
|
|
259
|
+
)
|
|
260
|
+
return bool(self._extract_result(result))
|
|
261
|
+
|
|
262
|
+
def insert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
263
|
+
"""Insert documents into the vector store.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
content_hash: The content hash for the documents.
|
|
267
|
+
documents: A list of documents to insert.
|
|
268
|
+
filters: A dictionary of filters to apply to the query.
|
|
269
|
+
|
|
270
|
+
"""
|
|
271
|
+
for doc in documents:
|
|
272
|
+
doc.embed(embedder=self.embedder)
|
|
273
|
+
meta_data: Dict[str, Any] = doc.meta_data if isinstance(doc.meta_data, dict) else {}
|
|
274
|
+
meta_data["content_hash"] = content_hash
|
|
275
|
+
data: Dict[str, Any] = {"content": doc.content, "embedding": doc.embedding, "meta_data": meta_data}
|
|
276
|
+
if filters:
|
|
277
|
+
data["meta_data"].update(filters)
|
|
278
|
+
self.client.create(self.collection, data)
|
|
279
|
+
|
|
280
|
+
def upsert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
281
|
+
"""Upsert documents into the vector store.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
content_hash: The content hash for the documents.
|
|
285
|
+
documents: A list of documents to upsert.
|
|
286
|
+
filters: A dictionary of filters to apply to the query.
|
|
287
|
+
|
|
288
|
+
"""
|
|
289
|
+
for doc in documents:
|
|
290
|
+
doc.embed(embedder=self.embedder)
|
|
291
|
+
meta_data: Dict[str, Any] = doc.meta_data if isinstance(doc.meta_data, dict) else {}
|
|
292
|
+
meta_data["content_hash"] = content_hash
|
|
293
|
+
data: Dict[str, Any] = {"content": doc.content, "embedding": doc.embedding, "meta_data": meta_data}
|
|
294
|
+
if filters:
|
|
295
|
+
data["meta_data"].update(filters)
|
|
296
|
+
thing = f"{self.collection}:{doc.id}" if doc.id else self.collection
|
|
297
|
+
self.client.query(self.UPSERT_QUERY.format(thing=thing), data)
|
|
298
|
+
|
|
299
|
+
def search(
|
|
300
|
+
self, query: str, limit: int = 5, filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
301
|
+
) -> List[Document]:
|
|
302
|
+
"""Search for similar documents.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
query: The query to search for.
|
|
306
|
+
limit: The maximum number of documents to return.
|
|
307
|
+
filters: A dictionary of filters to apply to the query.
|
|
308
|
+
|
|
309
|
+
Returns:
|
|
310
|
+
A list of documents that are similar to the query.
|
|
311
|
+
|
|
312
|
+
"""
|
|
313
|
+
if isinstance(filters, List):
|
|
314
|
+
log_warning("Filters Expressions are not supported in SurrealDB. No filters will be applied.")
|
|
315
|
+
filters = None
|
|
316
|
+
query_embedding = self.embedder.get_embedding(query)
|
|
317
|
+
if query_embedding is None:
|
|
318
|
+
log_error(f"Error getting embedding for Query: {query}")
|
|
319
|
+
return []
|
|
320
|
+
|
|
321
|
+
filter_condition = self._build_filter_condition(filters)
|
|
322
|
+
log_debug(f"Filter condition: {filter_condition}")
|
|
323
|
+
search_query = self.SEARCH_QUERY.format(
|
|
324
|
+
collection=self.collection,
|
|
325
|
+
limit=limit,
|
|
326
|
+
search_ef=self.search_ef,
|
|
327
|
+
filter_condition=filter_condition,
|
|
328
|
+
distance=self.distance,
|
|
329
|
+
)
|
|
330
|
+
log_debug(f"Search query: {search_query}")
|
|
331
|
+
response = self.client.query(
|
|
332
|
+
search_query,
|
|
333
|
+
{"query_embedding": query_embedding, **filters} if filters else {"query_embedding": query_embedding},
|
|
334
|
+
)
|
|
335
|
+
log_debug(f"Search response: {response}")
|
|
336
|
+
|
|
337
|
+
documents = []
|
|
338
|
+
for item in response:
|
|
339
|
+
if isinstance(item, dict):
|
|
340
|
+
doc = Document(
|
|
341
|
+
content=item.get("content", ""),
|
|
342
|
+
embedding=item.get("embedding", []),
|
|
343
|
+
meta_data=item.get("meta_data", {}),
|
|
344
|
+
embedder=self.embedder,
|
|
345
|
+
)
|
|
346
|
+
documents.append(doc)
|
|
347
|
+
log_debug(f"Found {len(documents)} documents")
|
|
348
|
+
return documents
|
|
349
|
+
|
|
350
|
+
def drop(self) -> None:
|
|
351
|
+
"""Drop the vector collection."""
|
|
352
|
+
log_debug(f"Dropping collection: {self.collection}")
|
|
353
|
+
self.client.query(self.DROP_TABLE_QUERY.format(collection=self.collection))
|
|
354
|
+
|
|
355
|
+
def exists(self) -> bool:
|
|
356
|
+
"""Check if the vector collection exists.
|
|
357
|
+
|
|
358
|
+
Returns:
|
|
359
|
+
True if the collection exists, False otherwise.
|
|
360
|
+
|
|
361
|
+
"""
|
|
362
|
+
log_debug(f"Checking if collection exists: {self.collection}")
|
|
363
|
+
response = self.client.query(self.INFO_DB_QUERY)
|
|
364
|
+
result = self._extract_result(response)
|
|
365
|
+
if isinstance(result, dict) and "tables" in result:
|
|
366
|
+
return self.collection in result["tables"]
|
|
367
|
+
return False
|
|
368
|
+
|
|
369
|
+
def delete(self) -> bool:
|
|
370
|
+
"""Delete all documents from the vector store.
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
True if the collection was deleted, False otherwise.
|
|
374
|
+
|
|
375
|
+
"""
|
|
376
|
+
self.client.query(self.DELETE_ALL_QUERY.format(collection=self.collection))
|
|
377
|
+
return True
|
|
378
|
+
|
|
379
|
+
def delete_by_id(self, id: str) -> bool:
|
|
380
|
+
"""Delete a document by its ID.
|
|
381
|
+
|
|
382
|
+
Args:
|
|
383
|
+
id: The ID of the document to delete.
|
|
384
|
+
|
|
385
|
+
Returns:
|
|
386
|
+
True if the document was deleted, False otherwise.
|
|
387
|
+
|
|
388
|
+
"""
|
|
389
|
+
log_debug(f"Deleting document by ID: {id}")
|
|
390
|
+
result = self.client.query(self.DELETE_BY_ID_QUERY.format(collection=self.collection), {"id": id})
|
|
391
|
+
return bool(result)
|
|
392
|
+
|
|
393
|
+
def delete_by_name(self, name: str) -> bool:
|
|
394
|
+
"""Delete documents by their name.
|
|
395
|
+
|
|
396
|
+
Args:
|
|
397
|
+
name: The name of the documents to delete.
|
|
398
|
+
|
|
399
|
+
Returns:
|
|
400
|
+
True if documents were deleted, False otherwise.
|
|
401
|
+
|
|
402
|
+
"""
|
|
403
|
+
log_debug(f"Deleting documents by name: {name}")
|
|
404
|
+
result = self.client.query(self.DELETE_BY_NAME_QUERY.format(collection=self.collection), {"name": name})
|
|
405
|
+
return bool(result)
|
|
406
|
+
|
|
407
|
+
def delete_by_metadata(self, metadata: Dict[str, Any]) -> bool:
|
|
408
|
+
"""Delete documents by their metadata.
|
|
409
|
+
|
|
410
|
+
Args:
|
|
411
|
+
metadata: The metadata to match for deletion.
|
|
412
|
+
|
|
413
|
+
Returns:
|
|
414
|
+
True if documents were deleted, False otherwise.
|
|
415
|
+
|
|
416
|
+
"""
|
|
417
|
+
log_debug(f"Deleting documents by metadata: {metadata}")
|
|
418
|
+
conditions = [f"meta_data.{key} = ${key}" for key in metadata.keys()]
|
|
419
|
+
conditions_str = " AND ".join(conditions)
|
|
420
|
+
query = self.DELETE_BY_METADATA_QUERY.format(collection=self.collection, conditions=conditions_str)
|
|
421
|
+
result = self.client.query(query, metadata)
|
|
422
|
+
return bool(result)
|
|
423
|
+
|
|
424
|
+
def delete_by_content_id(self, content_id: str) -> bool:
|
|
425
|
+
"""Delete documents by their content ID.
|
|
426
|
+
|
|
427
|
+
Args:
|
|
428
|
+
content_id: The content ID of the documents to delete.
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
True if documents were deleted, False otherwise.
|
|
432
|
+
|
|
433
|
+
"""
|
|
434
|
+
log_debug(f"Deleting documents by content ID: {content_id}")
|
|
435
|
+
result = self.client.query(
|
|
436
|
+
self.DELETE_BY_CONTENT_ID_QUERY.format(collection=self.collection), {"content_id": content_id}
|
|
437
|
+
)
|
|
438
|
+
return bool(result)
|
|
439
|
+
|
|
440
|
+
@staticmethod
|
|
441
|
+
def _extract_result(query_result: Union[List[Dict[str, Any]], Dict[str, Any]]) -> Union[List[Any], Dict[str, Any]]:
|
|
442
|
+
"""Extract the actual result from SurrealDB query response.
|
|
443
|
+
|
|
444
|
+
Args:
|
|
445
|
+
query_result: The query result from SurrealDB.
|
|
446
|
+
|
|
447
|
+
Returns:
|
|
448
|
+
The actual result from SurrealDB query response.
|
|
449
|
+
|
|
450
|
+
"""
|
|
451
|
+
log_debug(f"Query result: {query_result}")
|
|
452
|
+
if isinstance(query_result, dict):
|
|
453
|
+
return query_result
|
|
454
|
+
if isinstance(query_result, list):
|
|
455
|
+
if len(query_result) > 0:
|
|
456
|
+
return query_result[0].get("result", {})
|
|
457
|
+
return []
|
|
458
|
+
return []
|
|
459
|
+
|
|
460
|
+
async def async_create(self) -> None:
|
|
461
|
+
"""Create the vector collection and index asynchronously."""
|
|
462
|
+
log_debug(f"Creating collection: {self.collection}")
|
|
463
|
+
await self.async_client.query(
|
|
464
|
+
self.CREATE_TABLE_QUERY.format(
|
|
465
|
+
collection=self.collection,
|
|
466
|
+
distance=self.distance,
|
|
467
|
+
dimensions=self.dimensions,
|
|
468
|
+
efc=self.efc,
|
|
469
|
+
m=self.m,
|
|
470
|
+
),
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
async def async_name_exists(self, name: str) -> bool:
|
|
474
|
+
"""Check if a document exists by its name asynchronously.
|
|
475
|
+
|
|
476
|
+
Returns:
|
|
477
|
+
True if the document exists, False otherwise.
|
|
478
|
+
|
|
479
|
+
"""
|
|
480
|
+
response = await self.async_client.query(
|
|
481
|
+
self.NAME_EXISTS_QUERY.format(collection=self.collection),
|
|
482
|
+
{"name": name},
|
|
483
|
+
)
|
|
484
|
+
return bool(self._extract_result(response))
|
|
485
|
+
|
|
486
|
+
async def async_insert(
|
|
487
|
+
self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
|
|
488
|
+
) -> None:
|
|
489
|
+
"""Insert documents into the vector store asynchronously.
|
|
490
|
+
|
|
491
|
+
Args:
|
|
492
|
+
content_hash: The content hash for the documents.
|
|
493
|
+
documents: A list of documents to insert.
|
|
494
|
+
filters: A dictionary of filters to apply to the query.
|
|
495
|
+
|
|
496
|
+
"""
|
|
497
|
+
for doc in documents:
|
|
498
|
+
doc.embed(embedder=self.embedder)
|
|
499
|
+
meta_data: Dict[str, Any] = doc.meta_data if isinstance(doc.meta_data, dict) else {}
|
|
500
|
+
meta_data["content_hash"] = content_hash
|
|
501
|
+
data: Dict[str, Any] = {"content": doc.content, "embedding": doc.embedding, "meta_data": meta_data}
|
|
502
|
+
if filters:
|
|
503
|
+
data["meta_data"].update(filters)
|
|
504
|
+
log_debug(f"Inserting document asynchronously: {doc.name} ({doc.meta_data})")
|
|
505
|
+
await self.async_client.create(self.collection, data)
|
|
506
|
+
|
|
507
|
+
async def async_upsert(
|
|
508
|
+
self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
|
|
509
|
+
) -> None:
|
|
510
|
+
"""Upsert documents into the vector store asynchronously.
|
|
511
|
+
|
|
512
|
+
Args:
|
|
513
|
+
content_hash: The content hash for the documents.
|
|
514
|
+
documents: A list of documents to upsert.
|
|
515
|
+
filters: A dictionary of filters to apply to the query.
|
|
516
|
+
|
|
517
|
+
"""
|
|
518
|
+
for doc in documents:
|
|
519
|
+
doc.embed(embedder=self.embedder)
|
|
520
|
+
meta_data: Dict[str, Any] = doc.meta_data if isinstance(doc.meta_data, dict) else {}
|
|
521
|
+
meta_data["content_hash"] = content_hash
|
|
522
|
+
data: Dict[str, Any] = {"content": doc.content, "embedding": doc.embedding, "meta_data": meta_data}
|
|
523
|
+
if filters:
|
|
524
|
+
data["meta_data"].update(filters)
|
|
525
|
+
log_debug(f"Upserting document asynchronously: {doc.name} ({doc.meta_data})")
|
|
526
|
+
thing = f"{self.collection}:{doc.id}" if doc.id else self.collection
|
|
527
|
+
await self.async_client.query(self.UPSERT_QUERY.format(thing=thing), data)
|
|
528
|
+
|
|
529
|
+
async def async_search(
|
|
530
|
+
self,
|
|
531
|
+
query: str,
|
|
532
|
+
limit: int = 5,
|
|
533
|
+
filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
534
|
+
) -> List[Document]:
|
|
535
|
+
"""Search for similar documents asynchronously.
|
|
536
|
+
|
|
537
|
+
Args:
|
|
538
|
+
query: The query to search for.
|
|
539
|
+
limit: The maximum number of documents to return.
|
|
540
|
+
filters: A dictionary of filters to apply to the query.
|
|
541
|
+
|
|
542
|
+
Returns:
|
|
543
|
+
A list of documents that are similar to the query.
|
|
544
|
+
|
|
545
|
+
"""
|
|
546
|
+
if isinstance(filters, List):
|
|
547
|
+
log_warning("Filters Expressions are not supported in SurrealDB. No filters will be applied.")
|
|
548
|
+
filters = None
|
|
549
|
+
|
|
550
|
+
query_embedding = self.embedder.get_embedding(query)
|
|
551
|
+
if query_embedding is None:
|
|
552
|
+
log_error(f"Error getting embedding for Query: {query}")
|
|
553
|
+
return []
|
|
554
|
+
|
|
555
|
+
filter_condition = self._build_filter_condition(filters)
|
|
556
|
+
search_query = self.SEARCH_QUERY.format(
|
|
557
|
+
collection=self.collection,
|
|
558
|
+
limit=limit,
|
|
559
|
+
search_ef=self.search_ef,
|
|
560
|
+
filter_condition=filter_condition,
|
|
561
|
+
distance=self.distance,
|
|
562
|
+
)
|
|
563
|
+
response = await self.async_client.query(
|
|
564
|
+
search_query,
|
|
565
|
+
{"query_embedding": query_embedding, **filters} if filters else {"query_embedding": query_embedding},
|
|
566
|
+
)
|
|
567
|
+
log_debug(f"Search response: {response}")
|
|
568
|
+
documents = []
|
|
569
|
+
for item in response:
|
|
570
|
+
if isinstance(item, dict):
|
|
571
|
+
doc = Document(
|
|
572
|
+
content=item.get("content", ""),
|
|
573
|
+
embedding=item.get("embedding", []),
|
|
574
|
+
meta_data=item.get("meta_data", {}),
|
|
575
|
+
embedder=self.embedder,
|
|
576
|
+
)
|
|
577
|
+
documents.append(doc)
|
|
578
|
+
log_debug(f"Found {len(documents)} documents asynchronously")
|
|
579
|
+
return documents
|
|
580
|
+
|
|
581
|
+
async def async_drop(self) -> None:
|
|
582
|
+
"""Drop the vector collection asynchronously."""
|
|
583
|
+
log_debug(f"Dropping collection: {self.collection}")
|
|
584
|
+
await self.async_client.query(self.DROP_TABLE_QUERY.format(collection=self.collection))
|
|
585
|
+
|
|
586
|
+
async def async_exists(self) -> bool:
|
|
587
|
+
"""Check if the vector collection exists asynchronously.
|
|
588
|
+
|
|
589
|
+
Returns:
|
|
590
|
+
True if the collection exists, False otherwise.
|
|
591
|
+
|
|
592
|
+
"""
|
|
593
|
+
log_debug(f"Checking if collection exists: {self.collection}")
|
|
594
|
+
response = await self.async_client.query(self.INFO_DB_QUERY)
|
|
595
|
+
result = self._extract_result(response)
|
|
596
|
+
if isinstance(result, dict) and "tables" in result:
|
|
597
|
+
return self.collection in result["tables"]
|
|
598
|
+
return False
|
|
599
|
+
|
|
600
|
+
@staticmethod
|
|
601
|
+
def upsert_available() -> bool:
|
|
602
|
+
"""Check if upsert is available.
|
|
603
|
+
|
|
604
|
+
Returns:
|
|
605
|
+
True if upsert is available, False otherwise.
|
|
606
|
+
|
|
607
|
+
"""
|
|
608
|
+
return True
|
|
609
|
+
|
|
610
|
+
def update_metadata(self, content_id: str, metadata: Dict[str, Any]) -> None:
|
|
611
|
+
"""
|
|
612
|
+
Update the metadata for documents with the given content_id.
|
|
613
|
+
|
|
614
|
+
Args:
|
|
615
|
+
content_id (str): The content ID to update
|
|
616
|
+
metadata (Dict[str, Any]): The metadata to update
|
|
617
|
+
"""
|
|
618
|
+
try:
|
|
619
|
+
# Query for documents with the given content_id
|
|
620
|
+
query = f"SELECT * FROM {self.collection} WHERE content_id = $content_id"
|
|
621
|
+
result = self.client.query(query, {"content_id": content_id})
|
|
622
|
+
|
|
623
|
+
if not result or not result[0].get("result"):
|
|
624
|
+
log_debug(f"No documents found with content_id: {content_id}")
|
|
625
|
+
return
|
|
626
|
+
|
|
627
|
+
documents = result[0]["result"]
|
|
628
|
+
updated_count = 0
|
|
629
|
+
|
|
630
|
+
# Update each matching document
|
|
631
|
+
for doc in documents:
|
|
632
|
+
doc_id = doc["id"]
|
|
633
|
+
current_metadata = doc.get("meta_data", {})
|
|
634
|
+
current_filters = doc.get("filters", {})
|
|
635
|
+
|
|
636
|
+
# Merge existing metadata with new metadata
|
|
637
|
+
if isinstance(current_metadata, dict):
|
|
638
|
+
updated_metadata = current_metadata.copy()
|
|
639
|
+
updated_metadata.update(metadata)
|
|
640
|
+
else:
|
|
641
|
+
updated_metadata = metadata
|
|
642
|
+
|
|
643
|
+
# Merge existing filters with new metadata
|
|
644
|
+
if isinstance(current_filters, dict):
|
|
645
|
+
updated_filters = current_filters.copy()
|
|
646
|
+
updated_filters.update(metadata)
|
|
647
|
+
else:
|
|
648
|
+
updated_filters = metadata
|
|
649
|
+
|
|
650
|
+
# Update the document
|
|
651
|
+
update_query = f"UPDATE {doc_id} SET meta_data = $metadata, filters = $filters"
|
|
652
|
+
self.client.query(update_query, {"metadata": updated_metadata, "filters": updated_filters})
|
|
653
|
+
updated_count += 1
|
|
654
|
+
|
|
655
|
+
log_debug(f"Updated metadata for {updated_count} documents with content_id: {content_id}")
|
|
656
|
+
|
|
657
|
+
except Exception as e:
|
|
658
|
+
log_error(f"Error updating metadata for content_id '{content_id}': {e}")
|
|
659
|
+
raise
|
|
660
|
+
|
|
661
|
+
def get_supported_search_types(self) -> List[str]:
|
|
662
|
+
"""Get the supported search types for this vector database."""
|
|
663
|
+
return [] # SurrealDb doesn't use SearchType enum
|