agno 1.8.0__py3-none-any.whl → 2.0.0a1__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 +19 -27
- agno/agent/agent.py +2781 -4126
- agno/api/agent.py +9 -65
- agno/api/api.py +5 -46
- agno/api/evals.py +6 -17
- agno/api/os.py +17 -0
- agno/api/routes.py +6 -41
- agno/api/schemas/__init__.py +9 -0
- agno/api/schemas/agent.py +5 -21
- agno/api/schemas/evals.py +7 -16
- agno/api/schemas/os.py +14 -0
- agno/api/schemas/team.py +5 -21
- agno/api/schemas/utils.py +21 -0
- agno/api/schemas/workflows.py +11 -7
- agno/api/settings.py +53 -0
- agno/api/team.py +9 -64
- 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/db/__init__.py +24 -0
- agno/db/base.py +245 -0
- agno/db/dynamo/__init__.py +3 -0
- agno/db/dynamo/dynamo.py +1749 -0
- agno/db/dynamo/schemas.py +278 -0
- agno/db/dynamo/utils.py +684 -0
- agno/db/firestore/__init__.py +3 -0
- agno/db/firestore/firestore.py +1438 -0
- agno/db/firestore/schemas.py +130 -0
- agno/db/firestore/utils.py +278 -0
- agno/db/gcs_json/__init__.py +3 -0
- agno/db/gcs_json/gcs_json_db.py +1001 -0
- agno/db/gcs_json/utils.py +194 -0
- agno/db/in_memory/__init__.py +3 -0
- agno/db/in_memory/in_memory_db.py +888 -0
- agno/db/in_memory/utils.py +172 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1051 -0
- agno/db/json/utils.py +196 -0
- agno/db/migrations/v1_to_v2.py +162 -0
- agno/db/mongo/__init__.py +3 -0
- agno/db/mongo/mongo.py +1417 -0
- agno/db/mongo/schemas.py +77 -0
- agno/db/mongo/utils.py +204 -0
- agno/db/mysql/__init__.py +3 -0
- agno/db/mysql/mysql.py +1719 -0
- agno/db/mysql/schemas.py +124 -0
- agno/db/mysql/utils.py +298 -0
- agno/db/postgres/__init__.py +3 -0
- agno/db/postgres/postgres.py +1720 -0
- agno/db/postgres/schemas.py +124 -0
- agno/db/postgres/utils.py +281 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +1371 -0
- agno/db/redis/schemas.py +109 -0
- agno/db/redis/utils.py +288 -0
- agno/db/schemas/__init__.py +3 -0
- agno/db/schemas/evals.py +33 -0
- agno/db/schemas/knowledge.py +40 -0
- agno/db/schemas/memory.py +46 -0
- agno/db/singlestore/__init__.py +3 -0
- agno/db/singlestore/schemas.py +116 -0
- agno/db/singlestore/singlestore.py +1722 -0
- agno/db/singlestore/utils.py +327 -0
- agno/db/sqlite/__init__.py +3 -0
- agno/db/sqlite/schemas.py +119 -0
- agno/db/sqlite/sqlite.py +1680 -0
- agno/db/sqlite/utils.py +269 -0
- agno/db/utils.py +88 -0
- agno/eval/__init__.py +14 -0
- agno/eval/accuracy.py +142 -43
- agno/eval/performance.py +88 -23
- agno/eval/reliability.py +73 -20
- agno/eval/utils.py +23 -13
- agno/integrations/discord/__init__.py +3 -0
- agno/{app → integrations}/discord/client.py +10 -10
- agno/knowledge/__init__.py +2 -2
- agno/{document → knowledge}/chunking/agentic.py +2 -2
- agno/{document → knowledge}/chunking/document.py +2 -2
- agno/{document → knowledge}/chunking/fixed.py +3 -3
- agno/{document → knowledge}/chunking/markdown.py +2 -2
- agno/{document → knowledge}/chunking/recursive.py +2 -2
- agno/{document → knowledge}/chunking/row.py +2 -2
- agno/knowledge/chunking/semantic.py +59 -0
- agno/knowledge/chunking/strategy.py +121 -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/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
- agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
- agno/{embedder → knowledge/embedder}/base.py +6 -0
- agno/{embedder → knowledge/embedder}/cohere.py +72 -1
- agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
- agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
- agno/{embedder → knowledge/embedder}/google.py +74 -1
- agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
- agno/{embedder → knowledge/embedder}/jina.py +48 -2
- agno/knowledge/embedder/langdb.py +22 -0
- agno/knowledge/embedder/mistral.py +139 -0
- agno/{embedder → knowledge/embedder}/nebius.py +1 -1
- agno/{embedder → knowledge/embedder}/ollama.py +54 -3
- agno/knowledge/embedder/openai.py +223 -0
- agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
- agno/{embedder → knowledge/embedder}/together.py +1 -1
- agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
- agno/knowledge/knowledge.py +1515 -0
- agno/knowledge/reader/__init__.py +7 -0
- agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
- agno/knowledge/reader/base.py +88 -0
- agno/{document → knowledge}/reader/csv_reader.py +68 -15
- agno/knowledge/reader/docx_reader.py +83 -0
- agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
- agno/knowledge/reader/gcs_reader.py +67 -0
- agno/{document → knowledge}/reader/json_reader.py +30 -9
- agno/{document → knowledge}/reader/markdown_reader.py +36 -9
- agno/{document → knowledge}/reader/pdf_reader.py +79 -21
- agno/knowledge/reader/reader_factory.py +275 -0
- agno/knowledge/reader/s3_reader.py +171 -0
- agno/{document → knowledge}/reader/text_reader.py +31 -10
- agno/knowledge/reader/url_reader.py +84 -0
- agno/knowledge/reader/web_search_reader.py +389 -0
- agno/{document → knowledge}/reader/website_reader.py +37 -10
- agno/knowledge/reader/wikipedia_reader.py +59 -0
- agno/knowledge/reader/youtube_reader.py +78 -0
- agno/knowledge/remote_content/remote_content.py +88 -0
- agno/{reranker → knowledge/reranker}/base.py +1 -1
- agno/{reranker → knowledge/reranker}/cohere.py +2 -2
- agno/{reranker → knowledge/reranker}/infinity.py +2 -2
- agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
- agno/knowledge/types.py +30 -0
- agno/knowledge/utils.py +169 -0
- agno/media.py +2 -2
- agno/memory/__init__.py +2 -10
- agno/memory/manager.py +1003 -148
- agno/models/aimlapi/__init__.py +2 -2
- agno/models/aimlapi/aimlapi.py +6 -6
- agno/models/anthropic/claude.py +129 -82
- agno/models/aws/bedrock.py +107 -175
- agno/models/aws/claude.py +64 -18
- agno/models/azure/ai_foundry.py +73 -23
- agno/models/base.py +347 -287
- agno/models/cerebras/cerebras.py +84 -27
- agno/models/cohere/chat.py +106 -98
- agno/models/dashscope/dashscope.py +14 -5
- agno/models/google/gemini.py +123 -53
- agno/models/groq/groq.py +97 -35
- agno/models/huggingface/huggingface.py +92 -27
- agno/models/ibm/watsonx.py +72 -13
- agno/models/litellm/chat.py +85 -13
- agno/models/message.py +38 -144
- agno/models/meta/llama.py +85 -49
- agno/models/metrics.py +120 -0
- agno/models/mistral/mistral.py +90 -21
- agno/models/ollama/__init__.py +0 -2
- agno/models/ollama/chat.py +84 -46
- agno/models/openai/chat.py +135 -27
- agno/models/openai/responses.py +233 -115
- agno/models/perplexity/perplexity.py +26 -2
- agno/models/portkey/portkey.py +0 -7
- agno/models/response.py +14 -8
- agno/models/utils.py +20 -0
- agno/models/vercel/__init__.py +2 -2
- agno/models/vercel/v0.py +1 -1
- agno/models/vllm/__init__.py +2 -2
- agno/models/vllm/vllm.py +3 -3
- agno/models/xai/xai.py +10 -10
- agno/os/__init__.py +3 -0
- agno/os/app.py +393 -0
- agno/os/auth.py +47 -0
- agno/os/config.py +103 -0
- agno/os/interfaces/agui/__init__.py +3 -0
- agno/os/interfaces/agui/agui.py +31 -0
- agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
- agno/{app → os/interfaces}/agui/utils.py +65 -28
- agno/os/interfaces/base.py +21 -0
- agno/os/interfaces/slack/__init__.py +3 -0
- agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
- agno/os/interfaces/slack/slack.py +33 -0
- agno/os/interfaces/whatsapp/__init__.py +3 -0
- agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
- agno/os/interfaces/whatsapp/whatsapp.py +30 -0
- agno/os/router.py +843 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +204 -0
- agno/os/routers/evals/schemas.py +142 -0
- agno/os/routers/evals/utils.py +161 -0
- agno/os/routers/knowledge/__init__.py +3 -0
- agno/os/routers/knowledge/knowledge.py +413 -0
- agno/os/routers/knowledge/schemas.py +118 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +179 -0
- agno/os/routers/memory/schemas.py +58 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +58 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +163 -0
- agno/os/schema.py +892 -0
- agno/{app/playground → os}/settings.py +8 -15
- agno/os/utils.py +270 -0
- agno/reasoning/azure_ai_foundry.py +4 -4
- agno/reasoning/deepseek.py +4 -4
- agno/reasoning/default.py +6 -11
- agno/reasoning/groq.py +4 -4
- agno/reasoning/helpers.py +4 -6
- agno/reasoning/ollama.py +4 -4
- agno/reasoning/openai.py +4 -4
- agno/run/{response.py → agent.py} +144 -72
- agno/run/base.py +44 -58
- agno/run/cancel.py +83 -0
- agno/run/team.py +133 -77
- agno/run/workflow.py +537 -12
- agno/session/__init__.py +10 -0
- agno/session/agent.py +244 -0
- agno/session/summary.py +225 -0
- agno/session/team.py +262 -0
- agno/{storage/session/v2 → session}/workflow.py +47 -24
- agno/team/__init__.py +15 -16
- agno/team/team.py +2967 -4243
- agno/tools/agentql.py +14 -5
- agno/tools/airflow.py +9 -4
- agno/tools/api.py +7 -3
- agno/tools/apify.py +2 -46
- agno/tools/arxiv.py +8 -3
- agno/tools/aws_lambda.py +7 -5
- agno/tools/aws_ses.py +7 -1
- agno/tools/baidusearch.py +4 -1
- agno/tools/bitbucket.py +4 -4
- agno/tools/brandfetch.py +14 -11
- agno/tools/bravesearch.py +4 -1
- agno/tools/brightdata.py +42 -22
- agno/tools/browserbase.py +13 -4
- agno/tools/calcom.py +12 -10
- agno/tools/calculator.py +10 -27
- agno/tools/cartesia.py +18 -13
- agno/tools/{clickup_tool.py → clickup.py} +12 -25
- agno/tools/confluence.py +71 -18
- agno/tools/crawl4ai.py +7 -1
- agno/tools/csv_toolkit.py +9 -8
- agno/tools/dalle.py +18 -11
- agno/tools/daytona.py +13 -16
- agno/tools/decorator.py +6 -3
- agno/tools/desi_vocal.py +16 -7
- agno/tools/discord.py +11 -8
- agno/tools/docker.py +30 -42
- agno/tools/duckdb.py +34 -53
- agno/tools/duckduckgo.py +8 -7
- agno/tools/e2b.py +62 -62
- agno/tools/eleven_labs.py +35 -28
- agno/tools/email.py +4 -1
- agno/tools/evm.py +7 -1
- agno/tools/exa.py +19 -14
- agno/tools/fal.py +29 -29
- agno/tools/file.py +9 -8
- agno/tools/financial_datasets.py +25 -44
- agno/tools/firecrawl.py +22 -22
- agno/tools/function.py +68 -17
- agno/tools/giphy.py +22 -10
- agno/tools/github.py +48 -126
- agno/tools/gmail.py +46 -62
- agno/tools/google_bigquery.py +7 -6
- agno/tools/google_maps.py +11 -26
- agno/tools/googlesearch.py +7 -2
- agno/tools/googlesheets.py +21 -17
- agno/tools/hackernews.py +9 -5
- agno/tools/jina.py +5 -4
- agno/tools/jira.py +18 -9
- agno/tools/knowledge.py +31 -32
- agno/tools/linear.py +18 -33
- agno/tools/linkup.py +5 -1
- agno/tools/local_file_system.py +8 -5
- agno/tools/lumalab.py +31 -19
- agno/tools/mem0.py +18 -12
- agno/tools/memori.py +14 -10
- agno/tools/mlx_transcribe.py +3 -2
- agno/tools/models/azure_openai.py +32 -14
- agno/tools/models/gemini.py +58 -31
- agno/tools/models/groq.py +29 -20
- agno/tools/models/nebius.py +27 -11
- agno/tools/models_labs.py +39 -15
- agno/tools/moviepy_video.py +7 -6
- agno/tools/neo4j.py +134 -0
- agno/tools/newspaper.py +7 -2
- agno/tools/newspaper4k.py +8 -3
- agno/tools/openai.py +57 -26
- agno/tools/openbb.py +12 -11
- agno/tools/opencv.py +62 -46
- agno/tools/openweather.py +14 -12
- agno/tools/pandas.py +11 -3
- agno/tools/postgres.py +4 -12
- agno/tools/pubmed.py +4 -1
- agno/tools/python.py +9 -22
- agno/tools/reasoning.py +35 -27
- agno/tools/reddit.py +11 -26
- agno/tools/replicate.py +54 -41
- agno/tools/resend.py +4 -1
- agno/tools/scrapegraph.py +15 -14
- agno/tools/searxng.py +10 -23
- agno/tools/serpapi.py +6 -3
- agno/tools/serper.py +13 -4
- agno/tools/shell.py +9 -2
- agno/tools/slack.py +12 -11
- agno/tools/sleep.py +3 -2
- agno/tools/spider.py +24 -4
- agno/tools/sql.py +7 -6
- agno/tools/tavily.py +6 -4
- agno/tools/telegram.py +12 -4
- agno/tools/todoist.py +11 -31
- agno/tools/toolkit.py +1 -1
- agno/tools/trafilatura.py +22 -6
- agno/tools/trello.py +9 -22
- agno/tools/twilio.py +10 -3
- agno/tools/user_control_flow.py +6 -1
- agno/tools/valyu.py +34 -5
- agno/tools/visualization.py +19 -28
- agno/tools/webbrowser.py +4 -3
- agno/tools/webex.py +11 -7
- agno/tools/website.py +15 -46
- agno/tools/webtools.py +12 -4
- agno/tools/whatsapp.py +5 -9
- agno/tools/wikipedia.py +20 -13
- agno/tools/x.py +14 -13
- agno/tools/yfinance.py +13 -40
- agno/tools/youtube.py +26 -20
- agno/tools/zendesk.py +7 -2
- agno/tools/zep.py +10 -7
- agno/tools/zoom.py +10 -9
- agno/utils/common.py +1 -19
- agno/utils/events.py +95 -118
- agno/utils/knowledge.py +29 -0
- agno/utils/location.py +2 -2
- agno/utils/log.py +2 -2
- agno/utils/mcp.py +11 -5
- agno/utils/media.py +39 -0
- agno/utils/message.py +12 -1
- agno/utils/models/claude.py +6 -4
- agno/utils/models/mistral.py +8 -7
- agno/utils/models/schema_utils.py +3 -3
- agno/utils/pprint.py +33 -32
- agno/utils/print_response/agent.py +779 -0
- agno/utils/print_response/team.py +1565 -0
- agno/utils/print_response/workflow.py +1451 -0
- agno/utils/prompts.py +14 -14
- agno/utils/reasoning.py +87 -0
- agno/utils/response.py +42 -42
- agno/utils/string.py +8 -22
- agno/utils/team.py +50 -0
- agno/utils/timer.py +2 -2
- agno/vectordb/base.py +33 -21
- agno/vectordb/cassandra/cassandra.py +287 -23
- agno/vectordb/chroma/chromadb.py +482 -59
- agno/vectordb/clickhouse/clickhousedb.py +270 -63
- agno/vectordb/couchbase/couchbase.py +309 -29
- agno/vectordb/lancedb/lance_db.py +360 -21
- agno/vectordb/langchaindb/__init__.py +5 -0
- agno/vectordb/langchaindb/langchaindb.py +145 -0
- agno/vectordb/lightrag/__init__.py +5 -0
- agno/vectordb/lightrag/lightrag.py +374 -0
- agno/vectordb/llamaindex/llamaindexdb.py +127 -0
- agno/vectordb/milvus/milvus.py +242 -32
- agno/vectordb/mongodb/mongodb.py +200 -24
- agno/vectordb/pgvector/pgvector.py +319 -37
- agno/vectordb/pineconedb/pineconedb.py +221 -27
- agno/vectordb/qdrant/qdrant.py +356 -14
- agno/vectordb/singlestore/singlestore.py +286 -29
- agno/vectordb/surrealdb/surrealdb.py +187 -7
- agno/vectordb/upstashdb/upstashdb.py +342 -26
- agno/vectordb/weaviate/weaviate.py +227 -165
- agno/workflow/__init__.py +17 -13
- agno/workflow/{v2/condition.py → condition.py} +135 -32
- agno/workflow/{v2/loop.py → loop.py} +115 -28
- agno/workflow/{v2/parallel.py → parallel.py} +138 -108
- agno/workflow/{v2/router.py → router.py} +133 -32
- agno/workflow/{v2/step.py → step.py} +200 -42
- agno/workflow/{v2/steps.py → steps.py} +147 -66
- agno/workflow/types.py +482 -0
- agno/workflow/workflow.py +2394 -696
- agno-2.0.0a1.dist-info/METADATA +355 -0
- agno-2.0.0a1.dist-info/RECORD +514 -0
- agno/agent/metrics.py +0 -107
- agno/api/app.py +0 -35
- agno/api/playground.py +0 -92
- agno/api/schemas/app.py +0 -12
- agno/api/schemas/playground.py +0 -22
- agno/api/schemas/user.py +0 -35
- agno/api/schemas/workspace.py +0 -46
- agno/api/user.py +0 -160
- agno/api/workflows.py +0 -33
- agno/api/workspace.py +0 -175
- agno/app/agui/__init__.py +0 -3
- agno/app/agui/app.py +0 -17
- agno/app/agui/sync_router.py +0 -120
- agno/app/base.py +0 -186
- agno/app/discord/__init__.py +0 -3
- agno/app/fastapi/__init__.py +0 -3
- agno/app/fastapi/app.py +0 -107
- agno/app/fastapi/async_router.py +0 -457
- agno/app/fastapi/sync_router.py +0 -448
- agno/app/playground/app.py +0 -228
- agno/app/playground/async_router.py +0 -1050
- agno/app/playground/deploy.py +0 -249
- agno/app/playground/operator.py +0 -183
- agno/app/playground/schemas.py +0 -220
- agno/app/playground/serve.py +0 -55
- agno/app/playground/sync_router.py +0 -1042
- agno/app/playground/utils.py +0 -46
- agno/app/settings.py +0 -15
- agno/app/slack/__init__.py +0 -3
- agno/app/slack/app.py +0 -19
- agno/app/slack/sync_router.py +0 -92
- agno/app/utils.py +0 -54
- agno/app/whatsapp/__init__.py +0 -3
- agno/app/whatsapp/app.py +0 -15
- agno/app/whatsapp/sync_router.py +0 -197
- agno/cli/auth_server.py +0 -249
- agno/cli/config.py +0 -274
- agno/cli/console.py +0 -88
- agno/cli/credentials.py +0 -23
- agno/cli/entrypoint.py +0 -571
- agno/cli/operator.py +0 -357
- agno/cli/settings.py +0 -96
- agno/cli/ws/ws_cli.py +0 -817
- agno/constants.py +0 -13
- agno/document/__init__.py +0 -5
- agno/document/chunking/semantic.py +0 -45
- agno/document/chunking/strategy.py +0 -31
- agno/document/reader/__init__.py +0 -5
- agno/document/reader/base.py +0 -47
- agno/document/reader/docx_reader.py +0 -60
- agno/document/reader/gcs/pdf_reader.py +0 -44
- agno/document/reader/s3/pdf_reader.py +0 -59
- agno/document/reader/s3/text_reader.py +0 -63
- agno/document/reader/url_reader.py +0 -59
- agno/document/reader/youtube_reader.py +0 -58
- agno/embedder/__init__.py +0 -5
- agno/embedder/langdb.py +0 -80
- agno/embedder/mistral.py +0 -82
- agno/embedder/openai.py +0 -78
- agno/file/__init__.py +0 -5
- 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 -698
- agno/knowledge/arxiv.py +0 -33
- agno/knowledge/combined.py +0 -36
- agno/knowledge/csv.py +0 -144
- agno/knowledge/csv_url.py +0 -124
- agno/knowledge/document.py +0 -223
- agno/knowledge/docx.py +0 -137
- agno/knowledge/firecrawl.py +0 -34
- agno/knowledge/gcs/__init__.py +0 -0
- agno/knowledge/gcs/base.py +0 -39
- agno/knowledge/gcs/pdf.py +0 -125
- agno/knowledge/json.py +0 -137
- agno/knowledge/langchain.py +0 -71
- agno/knowledge/light_rag.py +0 -273
- agno/knowledge/llamaindex.py +0 -66
- agno/knowledge/markdown.py +0 -154
- agno/knowledge/pdf.py +0 -164
- agno/knowledge/pdf_bytes.py +0 -42
- agno/knowledge/pdf_url.py +0 -148
- agno/knowledge/s3/__init__.py +0 -0
- agno/knowledge/s3/base.py +0 -64
- agno/knowledge/s3/pdf.py +0 -33
- agno/knowledge/s3/text.py +0 -34
- agno/knowledge/text.py +0 -141
- agno/knowledge/url.py +0 -46
- agno/knowledge/website.py +0 -179
- agno/knowledge/wikipedia.py +0 -32
- agno/knowledge/youtube.py +0 -35
- agno/memory/agent.py +0 -423
- agno/memory/classifier.py +0 -104
- agno/memory/db/__init__.py +0 -5
- 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 -22
- agno/memory/row.py +0 -36
- agno/memory/summarizer.py +0 -201
- agno/memory/summary.py +0 -19
- agno/memory/team.py +0 -415
- agno/memory/v2/__init__.py +0 -2
- agno/memory/v2/db/__init__.py +0 -1
- agno/memory/v2/db/base.py +0 -42
- agno/memory/v2/db/firestore.py +0 -339
- agno/memory/v2/db/mongodb.py +0 -196
- agno/memory/v2/db/postgres.py +0 -214
- agno/memory/v2/db/redis.py +0 -187
- agno/memory/v2/db/schema.py +0 -54
- agno/memory/v2/db/sqlite.py +0 -209
- agno/memory/v2/manager.py +0 -437
- agno/memory/v2/memory.py +0 -1097
- agno/memory/v2/schema.py +0 -55
- agno/memory/v2/summarizer.py +0 -215
- agno/memory/workflow.py +0 -38
- agno/models/ollama/tools.py +0 -430
- agno/models/qwen/__init__.py +0 -5
- agno/playground/__init__.py +0 -10
- agno/playground/deploy.py +0 -3
- agno/playground/playground.py +0 -3
- agno/playground/serve.py +0 -3
- agno/playground/settings.py +0 -3
- agno/reranker/__init__.py +0 -0
- agno/run/v2/__init__.py +0 -0
- agno/run/v2/workflow.py +0 -567
- agno/storage/__init__.py +0 -0
- agno/storage/agent/__init__.py +0 -0
- agno/storage/agent/dynamodb.py +0 -1
- agno/storage/agent/json.py +0 -1
- agno/storage/agent/mongodb.py +0 -1
- agno/storage/agent/postgres.py +0 -1
- agno/storage/agent/singlestore.py +0 -1
- agno/storage/agent/sqlite.py +0 -1
- agno/storage/agent/yaml.py +0 -1
- agno/storage/base.py +0 -60
- agno/storage/dynamodb.py +0 -673
- agno/storage/firestore.py +0 -297
- agno/storage/gcs_json.py +0 -261
- agno/storage/in_memory.py +0 -234
- agno/storage/json.py +0 -237
- agno/storage/mongodb.py +0 -328
- agno/storage/mysql.py +0 -685
- agno/storage/postgres.py +0 -682
- agno/storage/redis.py +0 -336
- agno/storage/session/__init__.py +0 -16
- agno/storage/session/agent.py +0 -64
- agno/storage/session/team.py +0 -63
- agno/storage/session/v2/__init__.py +0 -5
- agno/storage/session/workflow.py +0 -61
- agno/storage/singlestore.py +0 -606
- agno/storage/sqlite.py +0 -646
- agno/storage/workflow/__init__.py +0 -0
- agno/storage/workflow/mongodb.py +0 -1
- agno/storage/workflow/postgres.py +0 -1
- agno/storage/workflow/sqlite.py +0 -1
- agno/storage/yaml.py +0 -241
- agno/tools/thinking.py +0 -73
- 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/workflow/v2/__init__.py +0 -21
- agno/workflow/v2/types.py +0 -357
- agno/workflow/v2/workflow.py +0 -3312
- agno/workspace/__init__.py +0 -0
- agno/workspace/config.py +0 -325
- agno/workspace/enums.py +0 -6
- agno/workspace/helpers.py +0 -52
- agno/workspace/operator.py +0 -757
- agno/workspace/settings.py +0 -158
- agno-1.8.0.dist-info/METADATA +0 -979
- agno-1.8.0.dist-info/RECORD +0 -565
- agno-1.8.0.dist-info/entry_points.txt +0 -3
- /agno/{app → db/migrations}/__init__.py +0 -0
- /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
- /agno/{cli → integrations}/__init__.py +0 -0
- /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
- /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
- /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
- /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
- /agno/{app → os/interfaces}/slack/security.py +0 -0
- /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
- /agno/{file/local → utils/print_response}/__init__.py +0 -0
- /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
- {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/WHEEL +0 -0
- {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
- {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/top_level.txt +0 -0
agno/vectordb/qdrant/qdrant.py
CHANGED
|
@@ -9,10 +9,10 @@ except ImportError:
|
|
|
9
9
|
"The `qdrant-client` package is not installed. Please install it via `pip install qdrant-client`."
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
-
from agno.document import Document
|
|
13
|
-
from agno.embedder import Embedder
|
|
14
|
-
from agno.reranker.base import Reranker
|
|
15
|
-
from agno.utils.log import log_debug, log_info
|
|
12
|
+
from agno.knowledge.document import Document
|
|
13
|
+
from agno.knowledge.embedder import Embedder
|
|
14
|
+
from agno.knowledge.reranker.base import Reranker
|
|
15
|
+
from agno.utils.log import log_debug, log_error, log_info, log_warning
|
|
16
16
|
from agno.vectordb.base import VectorDb
|
|
17
17
|
from agno.vectordb.distance import Distance
|
|
18
18
|
from agno.vectordb.search import SearchType
|
|
@@ -78,7 +78,7 @@ class Qdrant(VectorDb):
|
|
|
78
78
|
|
|
79
79
|
# Embedder for embedding the document contents
|
|
80
80
|
if embedder is None:
|
|
81
|
-
from agno.embedder.openai import OpenAIEmbedder
|
|
81
|
+
from agno.knowledge.embedder.openai import OpenAIEmbedder
|
|
82
82
|
|
|
83
83
|
embedder = OpenAIEmbedder()
|
|
84
84
|
log_info("Embedder not provided, using OpenAIEmbedder as default.")
|
|
@@ -302,7 +302,13 @@ class Qdrant(VectorDb):
|
|
|
302
302
|
return len(scroll_result[0]) > 0
|
|
303
303
|
return False
|
|
304
304
|
|
|
305
|
-
def insert(
|
|
305
|
+
def insert(
|
|
306
|
+
self,
|
|
307
|
+
content_hash: str,
|
|
308
|
+
documents: List[Document],
|
|
309
|
+
filters: Optional[Dict[str, Any]] = None,
|
|
310
|
+
batch_size: int = 10,
|
|
311
|
+
) -> None:
|
|
306
312
|
"""
|
|
307
313
|
Insert documents into the database.
|
|
308
314
|
|
|
@@ -343,6 +349,8 @@ class Qdrant(VectorDb):
|
|
|
343
349
|
"meta_data": document.meta_data,
|
|
344
350
|
"content": cleaned_content,
|
|
345
351
|
"usage": document.usage,
|
|
352
|
+
"content_id": document.content_id,
|
|
353
|
+
"content_hash": content_hash,
|
|
346
354
|
}
|
|
347
355
|
|
|
348
356
|
# Add filters as metadata if provided
|
|
@@ -364,7 +372,9 @@ class Qdrant(VectorDb):
|
|
|
364
372
|
self.client.upsert(collection_name=self.collection, wait=False, points=points)
|
|
365
373
|
log_debug(f"Upsert {len(points)} documents")
|
|
366
374
|
|
|
367
|
-
async def async_insert(
|
|
375
|
+
async def async_insert(
|
|
376
|
+
self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
|
|
377
|
+
) -> None:
|
|
368
378
|
"""
|
|
369
379
|
Insert documents asynchronously.
|
|
370
380
|
|
|
@@ -401,6 +411,8 @@ class Qdrant(VectorDb):
|
|
|
401
411
|
"meta_data": document.meta_data,
|
|
402
412
|
"content": cleaned_content,
|
|
403
413
|
"usage": document.usage,
|
|
414
|
+
"content_id": document.content_id,
|
|
415
|
+
"content_hash": content_hash,
|
|
404
416
|
}
|
|
405
417
|
|
|
406
418
|
# Add filters as metadata if provided
|
|
@@ -426,7 +438,7 @@ class Qdrant(VectorDb):
|
|
|
426
438
|
await self.async_client.upsert(collection_name=self.collection, wait=False, points=points)
|
|
427
439
|
log_debug(f"Upserted {len(points)} documents asynchronously")
|
|
428
440
|
|
|
429
|
-
def upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
441
|
+
def upsert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
430
442
|
"""
|
|
431
443
|
Upsert documents into the database.
|
|
432
444
|
|
|
@@ -435,12 +447,16 @@ class Qdrant(VectorDb):
|
|
|
435
447
|
filters (Optional[Dict[str, Any]]): Filters to apply while upserting
|
|
436
448
|
"""
|
|
437
449
|
log_debug("Redirecting the request to insert")
|
|
438
|
-
self.
|
|
450
|
+
if self.content_hash_exists(content_hash):
|
|
451
|
+
self._delete_by_content_hash(content_hash)
|
|
452
|
+
self.insert(content_hash=content_hash, documents=documents, filters=filters)
|
|
439
453
|
|
|
440
|
-
async def async_upsert(
|
|
454
|
+
async def async_upsert(
|
|
455
|
+
self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
|
|
456
|
+
) -> None:
|
|
441
457
|
"""Upsert documents asynchronously."""
|
|
442
458
|
log_debug("Redirecting the async request to async_insert")
|
|
443
|
-
await self.async_insert(documents, filters)
|
|
459
|
+
await self.async_insert(content_hash=content_hash, documents=documents, filters=filters)
|
|
444
460
|
|
|
445
461
|
def search(self, query: str, limit: int = 5, filters: Optional[Dict[str, Any]] = None) -> List[Document]:
|
|
446
462
|
"""
|
|
@@ -641,7 +657,8 @@ class Qdrant(VectorDb):
|
|
|
641
657
|
content=result.payload["content"],
|
|
642
658
|
embedder=self.embedder,
|
|
643
659
|
embedding=result.vector, # type: ignore
|
|
644
|
-
usage=result.payload
|
|
660
|
+
usage=result.payload.get("usage"),
|
|
661
|
+
content_id=result.payload.get("content_id"),
|
|
645
662
|
)
|
|
646
663
|
)
|
|
647
664
|
|
|
@@ -676,6 +693,9 @@ class Qdrant(VectorDb):
|
|
|
676
693
|
|
|
677
694
|
return None
|
|
678
695
|
|
|
696
|
+
def optimize(self) -> None:
|
|
697
|
+
pass
|
|
698
|
+
|
|
679
699
|
def drop(self) -> None:
|
|
680
700
|
if self.exists():
|
|
681
701
|
log_debug(f"Deleting collection: {self.collection}")
|
|
@@ -699,8 +719,330 @@ class Qdrant(VectorDb):
|
|
|
699
719
|
count_result: models.CountResult = self.client.count(collection_name=self.collection, exact=True)
|
|
700
720
|
return count_result.count
|
|
701
721
|
|
|
702
|
-
def
|
|
703
|
-
|
|
722
|
+
def point_exists(self, id: str) -> bool:
|
|
723
|
+
"""Check if a point with the given ID exists in the collection."""
|
|
724
|
+
try:
|
|
725
|
+
log_info(f"Checking if point with ID '{id}' (type: {type(id)}) exists in collection '{self.collection}'")
|
|
726
|
+
points = self.client.retrieve(
|
|
727
|
+
collection_name=self.collection, ids=[id], with_payload=False, with_vectors=False
|
|
728
|
+
)
|
|
729
|
+
log_info(f"Retrieved {len(points)} points for ID '{id}'")
|
|
730
|
+
if len(points) > 0:
|
|
731
|
+
log_info(f"Found point with ID: {points[0].id} (type: {type(points[0].id)})")
|
|
732
|
+
return len(points) > 0
|
|
733
|
+
except Exception as e:
|
|
734
|
+
log_info(f"Error checking if point {id} exists: {e}")
|
|
735
|
+
return False
|
|
704
736
|
|
|
705
737
|
def delete(self) -> bool:
|
|
706
738
|
return self.client.delete_collection(collection_name=self.collection)
|
|
739
|
+
|
|
740
|
+
def delete_by_id(self, id: str) -> bool:
|
|
741
|
+
try:
|
|
742
|
+
# Check if point exists before deletion
|
|
743
|
+
if not self.point_exists(id):
|
|
744
|
+
log_warning(f"Point with ID {id} does not exist")
|
|
745
|
+
return True
|
|
746
|
+
|
|
747
|
+
self.client.delete(
|
|
748
|
+
collection_name=self.collection,
|
|
749
|
+
points_selector=models.PointIdsList(points=[id]),
|
|
750
|
+
wait=True, # Wait for the operation to complete
|
|
751
|
+
)
|
|
752
|
+
return True
|
|
753
|
+
|
|
754
|
+
except Exception as e:
|
|
755
|
+
log_info(f"Error deleting point with ID {id}: {e}")
|
|
756
|
+
return False
|
|
757
|
+
|
|
758
|
+
def delete_by_name(self, name: str) -> bool:
|
|
759
|
+
"""Delete all points that have the specified name in their payload (precise match)."""
|
|
760
|
+
try:
|
|
761
|
+
log_info(f"Attempting to delete all points with name: {name}")
|
|
762
|
+
|
|
763
|
+
# Create a filter to find all points with the specified name (precise match)
|
|
764
|
+
filter_condition = models.Filter(
|
|
765
|
+
must=[models.FieldCondition(key="name", match=models.MatchValue(value=name))]
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
# First, count how many points will be deleted
|
|
769
|
+
count_result = self.client.count(collection_name=self.collection, count_filter=filter_condition, exact=True)
|
|
770
|
+
|
|
771
|
+
if count_result.count == 0:
|
|
772
|
+
log_warning(f"No points found with name: {name}")
|
|
773
|
+
return True
|
|
774
|
+
|
|
775
|
+
log_info(f"Found {count_result.count} points to delete with name: {name}")
|
|
776
|
+
|
|
777
|
+
# Delete all points matching the filter
|
|
778
|
+
result = self.client.delete(
|
|
779
|
+
collection_name=self.collection,
|
|
780
|
+
points_selector=filter_condition,
|
|
781
|
+
wait=True, # Wait for the operation to complete
|
|
782
|
+
)
|
|
783
|
+
|
|
784
|
+
# Check if the deletion was successful
|
|
785
|
+
if result.status == models.UpdateStatus.COMPLETED:
|
|
786
|
+
log_info(f"Successfully deleted {count_result.count} points with name: {name}")
|
|
787
|
+
return True
|
|
788
|
+
else:
|
|
789
|
+
log_warning(f"Deletion failed for name {name}. Status: {result.status}")
|
|
790
|
+
return False
|
|
791
|
+
|
|
792
|
+
except Exception as e:
|
|
793
|
+
log_warning(f"Error deleting points with name {name}: {e}")
|
|
794
|
+
return False
|
|
795
|
+
|
|
796
|
+
def delete_by_metadata(self, metadata: Dict[str, Any]) -> bool:
|
|
797
|
+
"""Delete all points where the given metadata is contained in the meta_data payload field."""
|
|
798
|
+
try:
|
|
799
|
+
log_info(f"Attempting to delete all points with metadata: {metadata}")
|
|
800
|
+
|
|
801
|
+
# Create filter conditions for each metadata key-value pair
|
|
802
|
+
filter_conditions = []
|
|
803
|
+
for key, value in metadata.items():
|
|
804
|
+
# Use the meta_data prefix since that's how metadata is stored in the payload
|
|
805
|
+
filter_conditions.append(
|
|
806
|
+
models.FieldCondition(key=f"meta_data.{key}", match=models.MatchValue(value=value))
|
|
807
|
+
)
|
|
808
|
+
|
|
809
|
+
# Create a filter that requires ALL metadata conditions to match
|
|
810
|
+
filter_condition = models.Filter(must=filter_conditions)
|
|
811
|
+
|
|
812
|
+
# First, count how many points will be deleted
|
|
813
|
+
count_result = self.client.count(collection_name=self.collection, count_filter=filter_condition, exact=True)
|
|
814
|
+
|
|
815
|
+
if count_result.count == 0:
|
|
816
|
+
log_warning(f"No points found with metadata: {metadata}")
|
|
817
|
+
return True
|
|
818
|
+
|
|
819
|
+
log_info(f"Found {count_result.count} points to delete with metadata: {metadata}")
|
|
820
|
+
|
|
821
|
+
# Delete all points matching the filter
|
|
822
|
+
result = self.client.delete(
|
|
823
|
+
collection_name=self.collection,
|
|
824
|
+
points_selector=filter_condition,
|
|
825
|
+
wait=True, # Wait for the operation to complete
|
|
826
|
+
)
|
|
827
|
+
|
|
828
|
+
# Check if the deletion was successful
|
|
829
|
+
if result.status == models.UpdateStatus.COMPLETED:
|
|
830
|
+
log_info(f"Successfully deleted {count_result.count} points with metadata: {metadata}")
|
|
831
|
+
return True
|
|
832
|
+
else:
|
|
833
|
+
log_warning(f"Deletion failed for metadata {metadata}. Status: {result.status}")
|
|
834
|
+
return False
|
|
835
|
+
|
|
836
|
+
except Exception as e:
|
|
837
|
+
log_warning(f"Error deleting points with metadata {metadata}: {e}")
|
|
838
|
+
return False
|
|
839
|
+
|
|
840
|
+
def delete_by_content_id(self, content_id: str) -> bool:
|
|
841
|
+
"""Delete all points that have the specified content_id in their payload."""
|
|
842
|
+
try:
|
|
843
|
+
log_info(f"Attempting to delete all points with content_id: {content_id}")
|
|
844
|
+
|
|
845
|
+
# Create a filter to find all points with the specified content_id
|
|
846
|
+
filter_condition = models.Filter(
|
|
847
|
+
must=[models.FieldCondition(key="content_id", match=models.MatchValue(value=content_id))]
|
|
848
|
+
)
|
|
849
|
+
|
|
850
|
+
# First, count how many points will be deleted
|
|
851
|
+
count_result = self.client.count(collection_name=self.collection, count_filter=filter_condition, exact=True)
|
|
852
|
+
|
|
853
|
+
if count_result.count == 0:
|
|
854
|
+
log_warning(f"No points found with content_id: {content_id}")
|
|
855
|
+
return True
|
|
856
|
+
|
|
857
|
+
log_info(f"Found {count_result.count} points to delete with content_id: {content_id}")
|
|
858
|
+
|
|
859
|
+
# Delete all points matching the filter
|
|
860
|
+
result = self.client.delete(
|
|
861
|
+
collection_name=self.collection,
|
|
862
|
+
points_selector=filter_condition,
|
|
863
|
+
wait=True, # Wait for the operation to complete
|
|
864
|
+
)
|
|
865
|
+
|
|
866
|
+
# Check if the deletion was successful
|
|
867
|
+
if result.status == models.UpdateStatus.COMPLETED:
|
|
868
|
+
log_info(f"Successfully deleted {count_result.count} points with content_id: {content_id}")
|
|
869
|
+
return True
|
|
870
|
+
else:
|
|
871
|
+
log_warning(f"Deletion failed for content_id {content_id}. Status: {result.status}")
|
|
872
|
+
return False
|
|
873
|
+
|
|
874
|
+
except Exception as e:
|
|
875
|
+
log_warning(f"Error deleting points with content_id {content_id}: {e}")
|
|
876
|
+
return False
|
|
877
|
+
|
|
878
|
+
def id_exists(self, id: str) -> bool:
|
|
879
|
+
"""Check if a point with the given ID exists in the collection.
|
|
880
|
+
|
|
881
|
+
Args:
|
|
882
|
+
id (str): The ID to check.
|
|
883
|
+
|
|
884
|
+
Returns:
|
|
885
|
+
bool: True if the point exists, False otherwise.
|
|
886
|
+
"""
|
|
887
|
+
try:
|
|
888
|
+
points = self.client.retrieve(
|
|
889
|
+
collection_name=self.collection, ids=[id], with_payload=False, with_vectors=False
|
|
890
|
+
)
|
|
891
|
+
return len(points) > 0
|
|
892
|
+
except Exception as e:
|
|
893
|
+
log_info(f"Error checking if point {id} exists: {e}")
|
|
894
|
+
return False
|
|
895
|
+
|
|
896
|
+
def content_hash_exists(self, content_hash: str) -> bool:
|
|
897
|
+
"""Check if any points with the given content hash exist in the collection.
|
|
898
|
+
|
|
899
|
+
Args:
|
|
900
|
+
content_hash (str): The content hash to check.
|
|
901
|
+
|
|
902
|
+
Returns:
|
|
903
|
+
bool: True if points with the content hash exist, False otherwise.
|
|
904
|
+
"""
|
|
905
|
+
try:
|
|
906
|
+
# Create a filter to find points with the specified content_hash
|
|
907
|
+
filter_condition = models.Filter(
|
|
908
|
+
must=[models.FieldCondition(key="content_hash", match=models.MatchValue(value=content_hash))]
|
|
909
|
+
)
|
|
910
|
+
|
|
911
|
+
# Count how many points match the filter
|
|
912
|
+
count_result = self.client.count(collection_name=self.collection, count_filter=filter_condition, exact=True)
|
|
913
|
+
return count_result.count > 0
|
|
914
|
+
except Exception as e:
|
|
915
|
+
log_info(f"Error checking if content_hash {content_hash} exists: {e}")
|
|
916
|
+
return False
|
|
917
|
+
|
|
918
|
+
def _delete_by_content_hash(self, content_hash: str) -> bool:
|
|
919
|
+
"""Delete all points that have the specified content_hash in their payload.
|
|
920
|
+
|
|
921
|
+
Args:
|
|
922
|
+
content_hash (str): The content hash to delete.
|
|
923
|
+
|
|
924
|
+
Returns:
|
|
925
|
+
bool: True if points were deleted successfully, False otherwise.
|
|
926
|
+
"""
|
|
927
|
+
try:
|
|
928
|
+
log_info(f"Attempting to delete all points with content_hash: {content_hash}")
|
|
929
|
+
|
|
930
|
+
# Create a filter to find all points with the specified content_hash
|
|
931
|
+
filter_condition = models.Filter(
|
|
932
|
+
must=[models.FieldCondition(key="content_hash", match=models.MatchValue(value=content_hash))]
|
|
933
|
+
)
|
|
934
|
+
|
|
935
|
+
# First, count how many points will be deleted
|
|
936
|
+
count_result = self.client.count(collection_name=self.collection, count_filter=filter_condition, exact=True)
|
|
937
|
+
|
|
938
|
+
if count_result.count == 0:
|
|
939
|
+
log_warning(f"No points found with content_hash: {content_hash}")
|
|
940
|
+
return True
|
|
941
|
+
|
|
942
|
+
log_info(f"Found {count_result.count} points to delete with content_hash: {content_hash}")
|
|
943
|
+
|
|
944
|
+
# Delete all points matching the filter
|
|
945
|
+
result = self.client.delete(
|
|
946
|
+
collection_name=self.collection,
|
|
947
|
+
points_selector=filter_condition,
|
|
948
|
+
wait=True, # Wait for the operation to complete
|
|
949
|
+
)
|
|
950
|
+
|
|
951
|
+
# Check if the deletion was successful
|
|
952
|
+
if result.status == models.UpdateStatus.COMPLETED:
|
|
953
|
+
log_info(f"Successfully deleted {count_result.count} points with content_hash: {content_hash}")
|
|
954
|
+
return True
|
|
955
|
+
else:
|
|
956
|
+
log_warning(f"Deletion failed for content_hash {content_hash}. Status: {result.status}")
|
|
957
|
+
return False
|
|
958
|
+
|
|
959
|
+
except Exception as e:
|
|
960
|
+
log_warning(f"Error deleting points with content_hash {content_hash}: {e}")
|
|
961
|
+
return False
|
|
962
|
+
|
|
963
|
+
def update_metadata(self, content_id: str, metadata: Dict[str, Any]) -> None:
|
|
964
|
+
"""
|
|
965
|
+
Update the metadata for documents with the given content_id.
|
|
966
|
+
|
|
967
|
+
Args:
|
|
968
|
+
content_id (str): The content ID to update
|
|
969
|
+
metadata (Dict[str, Any]): The metadata to update
|
|
970
|
+
"""
|
|
971
|
+
try:
|
|
972
|
+
if not self.client:
|
|
973
|
+
log_error("Client not initialized")
|
|
974
|
+
return
|
|
975
|
+
|
|
976
|
+
# Create filter for content_id
|
|
977
|
+
filter_condition = models.Filter(
|
|
978
|
+
must=[models.FieldCondition(key="content_id", match=models.MatchValue(value=content_id))]
|
|
979
|
+
)
|
|
980
|
+
|
|
981
|
+
# Search for points with the given content_id
|
|
982
|
+
search_result = self.client.scroll(
|
|
983
|
+
collection_name=self.collection,
|
|
984
|
+
scroll_filter=filter_condition,
|
|
985
|
+
limit=10000, # Get all matching points
|
|
986
|
+
with_payload=True,
|
|
987
|
+
with_vectors=False,
|
|
988
|
+
)
|
|
989
|
+
|
|
990
|
+
if not search_result[0]: # search_result is a tuple (points, next_page_offset)
|
|
991
|
+
log_error(f"No documents found with content_id: {content_id}")
|
|
992
|
+
return
|
|
993
|
+
|
|
994
|
+
points = search_result[0]
|
|
995
|
+
update_operations = []
|
|
996
|
+
|
|
997
|
+
# Prepare update operations for each point
|
|
998
|
+
for point in points:
|
|
999
|
+
point_id = point.id
|
|
1000
|
+
current_payload = point.payload or {}
|
|
1001
|
+
|
|
1002
|
+
# Merge existing metadata with new metadata
|
|
1003
|
+
updated_payload = current_payload.copy()
|
|
1004
|
+
updated_payload.update(metadata)
|
|
1005
|
+
|
|
1006
|
+
if "filters" not in updated_payload:
|
|
1007
|
+
updated_payload["filters"] = {}
|
|
1008
|
+
if isinstance(updated_payload["filters"], dict):
|
|
1009
|
+
updated_payload["filters"].update(metadata)
|
|
1010
|
+
else:
|
|
1011
|
+
updated_payload["filters"] = metadata
|
|
1012
|
+
|
|
1013
|
+
# Create set payload operation
|
|
1014
|
+
update_operations.append(models.SetPayload(payload=updated_payload, points=[point_id]))
|
|
1015
|
+
|
|
1016
|
+
# Execute all updates
|
|
1017
|
+
for operation in update_operations:
|
|
1018
|
+
self.client.set_payload(
|
|
1019
|
+
collection_name=self.collection, payload=operation.payload, points=operation.points
|
|
1020
|
+
)
|
|
1021
|
+
|
|
1022
|
+
log_debug(f"Updated metadata for {len(update_operations)} documents with content_id: {content_id}")
|
|
1023
|
+
|
|
1024
|
+
except Exception as e:
|
|
1025
|
+
log_error(f"Error updating metadata for content_id '{content_id}': {e}")
|
|
1026
|
+
raise
|
|
1027
|
+
|
|
1028
|
+
def close(self) -> None:
|
|
1029
|
+
"""Close the Qdrant client connections."""
|
|
1030
|
+
if self._client is not None:
|
|
1031
|
+
try:
|
|
1032
|
+
self._client.close()
|
|
1033
|
+
log_debug("Qdrant client closed successfully")
|
|
1034
|
+
except Exception as e:
|
|
1035
|
+
log_debug(f"Error closing Qdrant client: {e}")
|
|
1036
|
+
finally:
|
|
1037
|
+
self._client = None
|
|
1038
|
+
|
|
1039
|
+
async def async_close(self) -> None:
|
|
1040
|
+
"""Close the Qdrant client connections asynchronously."""
|
|
1041
|
+
if self._async_client is not None:
|
|
1042
|
+
try:
|
|
1043
|
+
await self._async_client.close()
|
|
1044
|
+
log_debug("Async Qdrant client closed successfully")
|
|
1045
|
+
except Exception as e:
|
|
1046
|
+
log_debug(f"Error closing async Qdrant client: {e}")
|
|
1047
|
+
finally:
|
|
1048
|
+
self._async_client = None
|