agno 1.8.1__py3-none-any.whl → 2.0.0rc1__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 +3181 -4169
- agno/api/agent.py +11 -67
- agno/api/api.py +5 -46
- agno/api/evals.py +8 -19
- 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 +11 -66
- 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 +1743 -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 +1432 -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 +882 -0
- agno/db/in_memory/utils.py +172 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1045 -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 +1411 -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 +297 -0
- agno/db/postgres/__init__.py +3 -0
- agno/db/postgres/postgres.py +1710 -0
- agno/db/postgres/schemas.py +124 -0
- agno/db/postgres/utils.py +280 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +1367 -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 +1712 -0
- agno/db/singlestore/utils.py +326 -0
- agno/db/sqlite/__init__.py +3 -0
- agno/db/sqlite/schemas.py +119 -0
- agno/db/sqlite/sqlite.py +1676 -0
- agno/db/sqlite/utils.py +268 -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 +15 -11
- 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/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 +131 -131
- 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/google/gemini.py +100 -42
- 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 +45 -150
- 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 +121 -23
- agno/models/openai/responses.py +178 -105
- 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 +489 -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 +77 -33
- 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 +32 -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 +29 -0
- agno/os/mcp.py +255 -0
- agno/os/router.py +869 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +208 -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 +436 -0
- agno/os/routers/knowledge/schemas.py +118 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +188 -0
- agno/os/routers/memory/schemas.py +58 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +60 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +168 -0
- agno/os/schema.py +892 -0
- agno/{app/playground → os}/settings.py +7 -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} +231 -74
- agno/run/base.py +44 -58
- agno/run/cancel.py +81 -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 +2960 -4252
- 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 +8 -8
- 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 +61 -61
- 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 +127 -18
- agno/tools/giphy.py +22 -10
- agno/tools/github.py +48 -126
- agno/tools/gmail.py +45 -61
- 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 +19 -34
- 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 +10 -8
- 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/gemini.py +31 -1
- agno/utils/knowledge.py +29 -0
- 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 +55 -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/streamlit.py +454 -0
- 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 +334 -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 +2401 -696
- agno-2.0.0rc1.dist-info/METADATA +355 -0
- agno-2.0.0rc1.dist-info/RECORD +516 -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 -702
- 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.1.dist-info/METADATA +0 -982
- agno-1.8.1.dist-info/RECORD +0 -566
- agno-1.8.1.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.1.dist-info → agno-2.0.0rc1.dist-info}/WHEEL +0 -0
- {agno-1.8.1.dist-info → agno-2.0.0rc1.dist-info}/licenses/LICENSE +0 -0
- {agno-1.8.1.dist-info → agno-2.0.0rc1.dist-info}/top_level.txt +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
import json
|
|
2
3
|
import uuid
|
|
3
4
|
from hashlib import md5
|
|
@@ -17,9 +18,9 @@ try:
|
|
|
17
18
|
except ImportError:
|
|
18
19
|
raise ImportError("Weaviate is not installed. Install using 'pip install weaviate-client'.")
|
|
19
20
|
|
|
20
|
-
from agno.document import Document
|
|
21
|
-
from agno.embedder import Embedder
|
|
22
|
-
from agno.reranker.base import Reranker
|
|
21
|
+
from agno.knowledge.document import Document
|
|
22
|
+
from agno.knowledge.embedder import Embedder
|
|
23
|
+
from agno.knowledge.reranker.base import Reranker
|
|
23
24
|
from agno.utils.log import log_debug, log_info, logger
|
|
24
25
|
from agno.vectordb.base import VectorDb
|
|
25
26
|
from agno.vectordb.search import SearchType
|
|
@@ -62,7 +63,7 @@ class Weaviate(VectorDb):
|
|
|
62
63
|
|
|
63
64
|
# Embedder setup
|
|
64
65
|
if embedder is None:
|
|
65
|
-
from agno.embedder.openai import OpenAIEmbedder
|
|
66
|
+
from agno.knowledge.embedder.openai import OpenAIEmbedder
|
|
66
67
|
|
|
67
68
|
embedder = OpenAIEmbedder()
|
|
68
69
|
log_info("Embedder not provided, using OpenAIEmbedder as default.")
|
|
@@ -139,6 +140,8 @@ class Weaviate(VectorDb):
|
|
|
139
140
|
Property(name="name", data_type=DataType.TEXT),
|
|
140
141
|
Property(name="content", data_type=DataType.TEXT, tokenization=Tokenization.LOWERCASE),
|
|
141
142
|
Property(name="meta_data", data_type=DataType.TEXT),
|
|
143
|
+
Property(name="content_id", data_type=DataType.TEXT),
|
|
144
|
+
Property(name="content_hash", data_type=DataType.TEXT),
|
|
142
145
|
],
|
|
143
146
|
vectorizer_config=Configure.Vectorizer.none(),
|
|
144
147
|
vector_index_config=self.get_vector_index_config(self.vector_index, self.distance),
|
|
@@ -154,6 +157,8 @@ class Weaviate(VectorDb):
|
|
|
154
157
|
Property(name="name", data_type=DataType.TEXT),
|
|
155
158
|
Property(name="content", data_type=DataType.TEXT, tokenization=Tokenization.LOWERCASE),
|
|
156
159
|
Property(name="meta_data", data_type=DataType.TEXT),
|
|
160
|
+
Property(name="content_id", data_type=DataType.TEXT),
|
|
161
|
+
Property(name="content_hash", data_type=DataType.TEXT),
|
|
157
162
|
],
|
|
158
163
|
vectorizer_config=Configure.Vectorizer.none(),
|
|
159
164
|
vector_index_config=self.get_vector_index_config(self.vector_index, self.distance),
|
|
@@ -162,95 +167,14 @@ class Weaviate(VectorDb):
|
|
|
162
167
|
finally:
|
|
163
168
|
await client.close()
|
|
164
169
|
|
|
165
|
-
def
|
|
166
|
-
"""
|
|
167
|
-
Check if the content of the document has changed by comparing its UUID.
|
|
168
|
-
|
|
169
|
-
Args:
|
|
170
|
-
document (Document): Document to check
|
|
171
|
-
|
|
172
|
-
Returns:
|
|
173
|
-
bool: True if the document content has changed, False otherwise. None on wrong input.
|
|
174
|
-
check_existing (bool): If True, check if the document exists before checking if the content changed.
|
|
175
|
-
"""
|
|
176
|
-
if not document or not document.content:
|
|
177
|
-
logger.warning("Invalid document: Missing content.")
|
|
178
|
-
return None
|
|
179
|
-
|
|
180
|
-
if check_existing and document.name and not self.name_exists(document.name):
|
|
181
|
-
logger.warning(f"A document by this name does not exist: {document.name}")
|
|
182
|
-
return None
|
|
183
|
-
|
|
184
|
-
doc_uuid, _ = self._get_doc_uuid(document)
|
|
185
|
-
|
|
186
|
-
collection = self.get_client().collections.get(self.collection)
|
|
187
|
-
existing_doc = collection.query.fetch_object_by_id(doc_uuid)
|
|
188
|
-
|
|
189
|
-
if not existing_doc:
|
|
190
|
-
return True
|
|
191
|
-
else:
|
|
192
|
-
return False
|
|
193
|
-
|
|
194
|
-
def doc_delete(self, name: str) -> None:
|
|
195
|
-
"""
|
|
196
|
-
Delete all documents from Weaviate with a specific 'name' property.
|
|
197
|
-
|
|
198
|
-
Args:
|
|
199
|
-
name (str): Document name to delete.
|
|
200
|
-
"""
|
|
201
|
-
collection = self.get_client().collections.get(self.collection)
|
|
202
|
-
filter_expr = Filter.by_property("name").equal(name)
|
|
203
|
-
|
|
204
|
-
result = collection.data.delete_many(where=filter_expr)
|
|
205
|
-
|
|
206
|
-
log_debug(f"Deleted document by name: '{name}' - {result.successful} documents deleted.")
|
|
207
|
-
if result.failed > 0:
|
|
208
|
-
logger.warning(
|
|
209
|
-
f"Failed to delete (some chunks of) document with name: '{name}' - "
|
|
210
|
-
f"Failed {result.failed} out of {result.matches} times. {result.successful} successful deletions."
|
|
211
|
-
)
|
|
212
|
-
|
|
213
|
-
def doc_exists(self, document: Document) -> bool:
|
|
214
|
-
"""
|
|
215
|
-
Validate if the document exists using consistent UUID generation.
|
|
216
|
-
|
|
217
|
-
Args:
|
|
218
|
-
document (Document): Document to validate
|
|
219
|
-
|
|
220
|
-
Returns:
|
|
221
|
-
bool: True if the document exists, False otherwise
|
|
222
|
-
"""
|
|
223
|
-
if not document or not document.content:
|
|
224
|
-
logger.warning("Invalid document: Missing content.")
|
|
225
|
-
return False # Early exit for invalid input
|
|
226
|
-
|
|
227
|
-
doc_uuid, _ = self._get_doc_uuid(document)
|
|
228
|
-
|
|
170
|
+
def content_hash_exists(self, content_hash: str) -> bool:
|
|
171
|
+
"""Check if a document with the given content hash exists in the collection."""
|
|
229
172
|
collection = self.get_client().collections.get(self.collection)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
Args:
|
|
237
|
-
document (Document): Document to validate
|
|
238
|
-
|
|
239
|
-
Returns:
|
|
240
|
-
bool: True if the document exists, False otherwise
|
|
241
|
-
"""
|
|
242
|
-
if not document or not document.content:
|
|
243
|
-
logger.warning("Invalid document: Missing content.")
|
|
244
|
-
return False # Early exit for invalid input
|
|
245
|
-
|
|
246
|
-
doc_uuid, _ = self._get_doc_uuid(document)
|
|
247
|
-
|
|
248
|
-
client = await self.get_async_client()
|
|
249
|
-
try:
|
|
250
|
-
collection = client.collections.get(self.collection)
|
|
251
|
-
return await collection.data.exists(doc_uuid)
|
|
252
|
-
finally:
|
|
253
|
-
await client.close()
|
|
173
|
+
result = collection.query.fetch_objects(
|
|
174
|
+
limit=1,
|
|
175
|
+
filters=Filter.by_property("content_hash").equal(content_hash),
|
|
176
|
+
)
|
|
177
|
+
return len(result.objects) > 0
|
|
254
178
|
|
|
255
179
|
def name_exists(self, name: str) -> bool:
|
|
256
180
|
"""
|
|
@@ -290,7 +214,7 @@ class Weaviate(VectorDb):
|
|
|
290
214
|
finally:
|
|
291
215
|
await client.close()
|
|
292
216
|
|
|
293
|
-
def insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
217
|
+
def insert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
294
218
|
"""
|
|
295
219
|
Insert documents into Weaviate.
|
|
296
220
|
|
|
@@ -307,7 +231,9 @@ class Weaviate(VectorDb):
|
|
|
307
231
|
logger.error(f"Document embedding is None: {document.name}")
|
|
308
232
|
continue
|
|
309
233
|
|
|
310
|
-
|
|
234
|
+
cleaned_content = document.content.replace("\x00", "\ufffd")
|
|
235
|
+
record_id = md5(cleaned_content.encode()).hexdigest()
|
|
236
|
+
doc_uuid = uuid.UUID(hex=record_id[:32])
|
|
311
237
|
|
|
312
238
|
# Merge filters with metadata
|
|
313
239
|
meta_data = document.meta_data or {}
|
|
@@ -322,13 +248,17 @@ class Weaviate(VectorDb):
|
|
|
322
248
|
"name": document.name,
|
|
323
249
|
"content": cleaned_content,
|
|
324
250
|
"meta_data": meta_data_str,
|
|
251
|
+
"content_id": document.content_id,
|
|
252
|
+
"content_hash": content_hash,
|
|
325
253
|
},
|
|
326
254
|
vector=document.embedding,
|
|
327
255
|
uuid=doc_uuid,
|
|
328
256
|
)
|
|
329
257
|
log_debug(f"Inserted document: {document.name} ({meta_data})")
|
|
330
258
|
|
|
331
|
-
async def async_insert(
|
|
259
|
+
async def async_insert(
|
|
260
|
+
self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
|
|
261
|
+
) -> None:
|
|
332
262
|
"""
|
|
333
263
|
Insert documents into Weaviate asynchronously.
|
|
334
264
|
|
|
@@ -340,6 +270,10 @@ class Weaviate(VectorDb):
|
|
|
340
270
|
if not documents:
|
|
341
271
|
return
|
|
342
272
|
|
|
273
|
+
# Embed document
|
|
274
|
+
embed_tasks = [document.async_embed(embedder=self.embedder) for document in documents]
|
|
275
|
+
await asyncio.gather(*embed_tasks, return_exceptions=True)
|
|
276
|
+
|
|
343
277
|
client = await self.get_async_client()
|
|
344
278
|
try:
|
|
345
279
|
collection = client.collections.get(self.collection)
|
|
@@ -347,14 +281,14 @@ class Weaviate(VectorDb):
|
|
|
347
281
|
# Process documents first
|
|
348
282
|
for document in documents:
|
|
349
283
|
try:
|
|
350
|
-
# Embed document
|
|
351
|
-
document.embed(embedder=self.embedder)
|
|
352
284
|
if document.embedding is None:
|
|
353
285
|
logger.error(f"Document embedding is None: {document.name}")
|
|
354
286
|
continue
|
|
355
287
|
|
|
356
288
|
# Clean content and generate UUID
|
|
357
|
-
|
|
289
|
+
cleaned_content = document.content.replace("\x00", "\ufffd")
|
|
290
|
+
record_id = md5(cleaned_content.encode()).hexdigest()
|
|
291
|
+
doc_uuid = uuid.UUID(hex=record_id[:32])
|
|
358
292
|
|
|
359
293
|
# Serialize meta_data to JSON string
|
|
360
294
|
meta_data_str = json.dumps(document.meta_data) if document.meta_data else None
|
|
@@ -364,6 +298,8 @@ class Weaviate(VectorDb):
|
|
|
364
298
|
"name": document.name,
|
|
365
299
|
"content": cleaned_content,
|
|
366
300
|
"meta_data": meta_data_str,
|
|
301
|
+
"content_id": document.content_id,
|
|
302
|
+
"content_hash": content_hash,
|
|
367
303
|
}
|
|
368
304
|
|
|
369
305
|
# Use the API correctly - properties, vector and uuid are separate parameters
|
|
@@ -376,7 +312,7 @@ class Weaviate(VectorDb):
|
|
|
376
312
|
finally:
|
|
377
313
|
await client.close()
|
|
378
314
|
|
|
379
|
-
def upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
315
|
+
def upsert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
380
316
|
"""
|
|
381
317
|
Upsert documents into Weaviate.
|
|
382
318
|
|
|
@@ -385,30 +321,13 @@ class Weaviate(VectorDb):
|
|
|
385
321
|
filters (Optional[Dict[str, Any]]): Filters to apply while upserting
|
|
386
322
|
"""
|
|
387
323
|
log_debug(f"Upserting {len(documents)} documents into Weaviate.")
|
|
324
|
+
if self.content_hash_exists(content_hash):
|
|
325
|
+
self._delete_by_content_hash(content_hash)
|
|
326
|
+
self.insert(content_hash=content_hash, documents=documents, filters=filters)
|
|
388
327
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
if self.name_exists(document.name):
|
|
394
|
-
if self.doc_content_changed(document, check_existing=False):
|
|
395
|
-
log_debug(
|
|
396
|
-
f"Document already exists, but content changed. Document will be deleted and added again: {document.name}"
|
|
397
|
-
)
|
|
398
|
-
|
|
399
|
-
is_first_or_only_chunk = ("chunk" in document.meta_data and document.meta_data["chunk"] == 1) or (
|
|
400
|
-
"chunk" not in document.meta_data
|
|
401
|
-
)
|
|
402
|
-
if is_first_or_only_chunk:
|
|
403
|
-
self.doc_delete(document.name)
|
|
404
|
-
_docs_to_insert.append(document)
|
|
405
|
-
else:
|
|
406
|
-
log_debug(f"Document skipped, content is unchanged: {document.name}")
|
|
407
|
-
else:
|
|
408
|
-
_docs_to_insert.append(document)
|
|
409
|
-
self.insert(_docs_to_insert)
|
|
410
|
-
|
|
411
|
-
async def async_upsert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
328
|
+
async def async_upsert(
|
|
329
|
+
self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
|
|
330
|
+
) -> None:
|
|
412
331
|
"""
|
|
413
332
|
Upsert documents into Weaviate asynchronously.
|
|
414
333
|
When documents with the same ID already exist, they will be replaced.
|
|
@@ -418,37 +337,10 @@ class Weaviate(VectorDb):
|
|
|
418
337
|
documents (List[Document]): List of documents to upsert
|
|
419
338
|
filters (Optional[Dict[str, Any]]): Filters to apply while upserting
|
|
420
339
|
"""
|
|
421
|
-
if
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
client = await self.get_async_client()
|
|
427
|
-
try:
|
|
428
|
-
collection = client.collections.get(self.collection)
|
|
429
|
-
|
|
430
|
-
for document in documents:
|
|
431
|
-
document.embed(embedder=self.embedder)
|
|
432
|
-
if document.embedding is None:
|
|
433
|
-
logger.error(f"Document embedding is None: {document.name}")
|
|
434
|
-
continue
|
|
435
|
-
|
|
436
|
-
doc_uuid, cleaned_content = self._get_doc_uuid(document)
|
|
437
|
-
|
|
438
|
-
# Serialize meta_data to JSON string
|
|
439
|
-
meta_data_str = json.dumps(document.meta_data) if document.meta_data else None
|
|
440
|
-
|
|
441
|
-
properties = {
|
|
442
|
-
"name": document.name,
|
|
443
|
-
"content": cleaned_content,
|
|
444
|
-
"meta_data": meta_data_str,
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
await collection.data.replace(uuid=doc_uuid, properties=properties, vector=document.embedding)
|
|
448
|
-
|
|
449
|
-
log_debug(f"Upserted document asynchronously: {document.name}")
|
|
450
|
-
finally:
|
|
451
|
-
await client.close()
|
|
340
|
+
if self.content_hash_exists(content_hash):
|
|
341
|
+
self._delete_by_content_hash(content_hash)
|
|
342
|
+
await self.async_insert(content_hash=content_hash, documents=documents, filters=filters)
|
|
343
|
+
return
|
|
452
344
|
|
|
453
345
|
def search(self, query: str, limit: int = 5, filters: Optional[Dict[str, Any]] = None) -> List[Document]:
|
|
454
346
|
"""
|
|
@@ -509,7 +401,7 @@ class Weaviate(VectorDb):
|
|
|
509
401
|
response = collection.query.near_vector(
|
|
510
402
|
near_vector=query_embedding,
|
|
511
403
|
limit=limit,
|
|
512
|
-
return_properties=["name", "content", "meta_data"],
|
|
404
|
+
return_properties=["name", "content", "meta_data", "content_id"],
|
|
513
405
|
include_vector=True,
|
|
514
406
|
filters=filter_expr,
|
|
515
407
|
)
|
|
@@ -557,7 +449,7 @@ class Weaviate(VectorDb):
|
|
|
557
449
|
response = await collection.query.near_vector(
|
|
558
450
|
near_vector=query_embedding,
|
|
559
451
|
limit=limit,
|
|
560
|
-
return_properties=["name", "content", "meta_data"],
|
|
452
|
+
return_properties=["name", "content", "meta_data", "content_id"],
|
|
561
453
|
include_vector=True,
|
|
562
454
|
filters=filter_expr,
|
|
563
455
|
)
|
|
@@ -585,7 +477,7 @@ class Weaviate(VectorDb):
|
|
|
585
477
|
query=query,
|
|
586
478
|
query_properties=["content"],
|
|
587
479
|
limit=limit,
|
|
588
|
-
return_properties=["name", "content", "meta_data"],
|
|
480
|
+
return_properties=["name", "content", "meta_data", "content_id"],
|
|
589
481
|
include_vector=True,
|
|
590
482
|
filters=filter_expr,
|
|
591
483
|
)
|
|
@@ -629,7 +521,7 @@ class Weaviate(VectorDb):
|
|
|
629
521
|
query=query,
|
|
630
522
|
query_properties=["content"],
|
|
631
523
|
limit=limit,
|
|
632
|
-
return_properties=["name", "content", "meta_data"],
|
|
524
|
+
return_properties=["name", "content", "meta_data", "content_id"],
|
|
633
525
|
include_vector=True,
|
|
634
526
|
filters=filter_expr,
|
|
635
527
|
)
|
|
@@ -662,7 +554,7 @@ class Weaviate(VectorDb):
|
|
|
662
554
|
query=query,
|
|
663
555
|
vector=query_embedding,
|
|
664
556
|
limit=limit,
|
|
665
|
-
return_properties=["name", "content", "meta_data"],
|
|
557
|
+
return_properties=["name", "content", "meta_data", "content_id"],
|
|
666
558
|
include_vector=True,
|
|
667
559
|
query_properties=["content"],
|
|
668
560
|
alpha=self.hybrid_search_alpha,
|
|
@@ -713,7 +605,7 @@ class Weaviate(VectorDb):
|
|
|
713
605
|
query=query,
|
|
714
606
|
vector=query_embedding,
|
|
715
607
|
limit=limit,
|
|
716
|
-
return_properties=["name", "content", "meta_data"],
|
|
608
|
+
return_properties=["name", "content", "meta_data", "content_id"],
|
|
717
609
|
include_vector=True,
|
|
718
610
|
query_properties=["content"],
|
|
719
611
|
alpha=self.hybrid_search_alpha,
|
|
@@ -771,6 +663,86 @@ class Weaviate(VectorDb):
|
|
|
771
663
|
self.drop()
|
|
772
664
|
return True
|
|
773
665
|
|
|
666
|
+
def delete_by_id(self, id: str) -> bool:
|
|
667
|
+
"""Delete document by ID."""
|
|
668
|
+
try:
|
|
669
|
+
try:
|
|
670
|
+
doc_uuid = uuid.UUID(hex=id[:32]) if len(id) == 32 else uuid.UUID(id)
|
|
671
|
+
except ValueError:
|
|
672
|
+
log_info(f"Invalid UUID format for ID '{id}' - treating as non-existent")
|
|
673
|
+
return True
|
|
674
|
+
|
|
675
|
+
collection = self.get_client().collections.get(self.collection)
|
|
676
|
+
|
|
677
|
+
if not collection.data.exists(doc_uuid):
|
|
678
|
+
log_info(f"Document with ID {id} does not exist")
|
|
679
|
+
return True
|
|
680
|
+
|
|
681
|
+
collection.data.delete_by_id(doc_uuid)
|
|
682
|
+
log_info(f"Deleted document with ID '{id}' from collection '{self.collection}'.")
|
|
683
|
+
return True
|
|
684
|
+
except Exception as e:
|
|
685
|
+
logger.error(f"Error deleting document by ID '{id}': {e}")
|
|
686
|
+
return False
|
|
687
|
+
|
|
688
|
+
def delete_by_name(self, name: str) -> bool:
|
|
689
|
+
"""Delete content by name using direct filter deletion."""
|
|
690
|
+
try:
|
|
691
|
+
collection = self.get_client().collections.get(self.collection)
|
|
692
|
+
|
|
693
|
+
collection.data.delete_many(where=Filter.by_property("name").equal(name))
|
|
694
|
+
|
|
695
|
+
log_info(f"Deleted documents with name '{name}' from collection '{self.collection}'.")
|
|
696
|
+
return True
|
|
697
|
+
|
|
698
|
+
except Exception as e:
|
|
699
|
+
logger.error(f"Error deleting documents by name '{name}': {e}")
|
|
700
|
+
return False
|
|
701
|
+
|
|
702
|
+
def delete_by_metadata(self, metadata: Dict[str, Any]) -> bool:
|
|
703
|
+
"""Delete content by metadata using direct filter deletion."""
|
|
704
|
+
try:
|
|
705
|
+
collection = self.get_client().collections.get(self.collection)
|
|
706
|
+
|
|
707
|
+
# Build filter for metadata search
|
|
708
|
+
filter_expr = self._build_filter_expression(metadata)
|
|
709
|
+
if filter_expr is None:
|
|
710
|
+
log_info(f"No valid filter could be built for metadata: {metadata}")
|
|
711
|
+
return False
|
|
712
|
+
|
|
713
|
+
collection.data.delete_many(where=filter_expr)
|
|
714
|
+
|
|
715
|
+
log_info(f"Deleted documents with metadata '{metadata}' from collection '{self.collection}'.")
|
|
716
|
+
return True
|
|
717
|
+
|
|
718
|
+
except Exception as e:
|
|
719
|
+
logger.error(f"Error deleting documents by metadata '{metadata}': {e}")
|
|
720
|
+
return False
|
|
721
|
+
|
|
722
|
+
def delete_by_content_id(self, content_id: str) -> bool:
|
|
723
|
+
"""Delete content by content ID using direct filter deletion."""
|
|
724
|
+
try:
|
|
725
|
+
collection = self.get_client().collections.get(self.collection)
|
|
726
|
+
|
|
727
|
+
collection.data.delete_many(where=Filter.by_property("content_id").equal(content_id))
|
|
728
|
+
|
|
729
|
+
log_info(f"Deleted documents with content_id '{content_id}' from collection '{self.collection}'.")
|
|
730
|
+
return True
|
|
731
|
+
|
|
732
|
+
except Exception as e:
|
|
733
|
+
logger.error(f"Error deleting documents by content_id '{content_id}': {e}")
|
|
734
|
+
return False
|
|
735
|
+
|
|
736
|
+
def delete_by_content_hash(self, content_hash: str) -> bool:
|
|
737
|
+
"""Delete content by content hash using direct filter deletion."""
|
|
738
|
+
try:
|
|
739
|
+
collection = self.get_client().collections.get(self.collection)
|
|
740
|
+
collection.data.delete_many(where=Filter.by_property("content_hash").equal(content_hash))
|
|
741
|
+
return True
|
|
742
|
+
except Exception as e:
|
|
743
|
+
logger.error(f"Error deleting documents by content_hash '{content_hash}': {e}")
|
|
744
|
+
return False
|
|
745
|
+
|
|
774
746
|
def get_vector_index_config(self, index_type: VectorIndex, distance_metric: Distance):
|
|
775
747
|
"""
|
|
776
748
|
Returns the appropriate vector index configuration with the specified distance metric.
|
|
@@ -807,17 +779,17 @@ class Weaviate(VectorDb):
|
|
|
807
779
|
search_results: List[Document] = []
|
|
808
780
|
for obj in response.objects:
|
|
809
781
|
properties = obj.properties
|
|
810
|
-
meta_data = json.loads(properties["meta_data"]) if properties.get("meta_data") else
|
|
782
|
+
meta_data = json.loads(properties["meta_data"]) if properties.get("meta_data") else {}
|
|
811
783
|
embedding = obj.vector["default"] if isinstance(obj.vector, dict) else obj.vector
|
|
812
784
|
|
|
813
785
|
search_results.append(
|
|
814
786
|
Document(
|
|
815
|
-
name=properties
|
|
816
|
-
meta_data=meta_data
|
|
817
|
-
content=properties
|
|
787
|
+
name=properties.get("name"),
|
|
788
|
+
meta_data=meta_data,
|
|
789
|
+
content=properties.get("content", ""),
|
|
818
790
|
embedder=self.embedder,
|
|
819
791
|
embedding=embedding,
|
|
820
|
-
|
|
792
|
+
content_id=properties.get("content_id"),
|
|
821
793
|
)
|
|
822
794
|
)
|
|
823
795
|
|
|
@@ -827,7 +799,7 @@ class Weaviate(VectorDb):
|
|
|
827
799
|
"""Indicate that upsert functionality is available."""
|
|
828
800
|
return True
|
|
829
801
|
|
|
830
|
-
def _build_filter_expression(self, filters: Optional[Dict[str, Any]])
|
|
802
|
+
def _build_filter_expression(self, filters: Optional[Dict[str, Any]]):
|
|
831
803
|
"""
|
|
832
804
|
Build a filter expression for Weaviate queries.
|
|
833
805
|
|
|
@@ -870,3 +842,93 @@ class Weaviate(VectorDb):
|
|
|
870
842
|
return None
|
|
871
843
|
|
|
872
844
|
return None
|
|
845
|
+
|
|
846
|
+
def id_exists(self, id: str) -> bool:
|
|
847
|
+
"""Check if a document with the given ID exists in the collection.
|
|
848
|
+
|
|
849
|
+
Args:
|
|
850
|
+
id (str): The document ID to check.
|
|
851
|
+
|
|
852
|
+
Returns:
|
|
853
|
+
bool: True if the document exists, False otherwise.
|
|
854
|
+
"""
|
|
855
|
+
try:
|
|
856
|
+
doc_uuid = uuid.UUID(hex=id[:32]) if len(id) == 32 else uuid.UUID(id)
|
|
857
|
+
collection = self.get_client().collections.get(self.collection)
|
|
858
|
+
return collection.data.exists(doc_uuid)
|
|
859
|
+
except ValueError:
|
|
860
|
+
log_info(f"Invalid UUID format for ID '{id}' - treating as non-existent")
|
|
861
|
+
return False
|
|
862
|
+
except Exception as e:
|
|
863
|
+
logger.error(f"Error checking if ID '{id}' exists: {e}")
|
|
864
|
+
return False
|
|
865
|
+
|
|
866
|
+
def update_metadata(self, content_id: str, metadata: Dict[str, Any]) -> None:
|
|
867
|
+
"""
|
|
868
|
+
Update the metadata for documents with the given content_id.
|
|
869
|
+
|
|
870
|
+
Args:
|
|
871
|
+
content_id (str): The content ID to update
|
|
872
|
+
metadata (Dict[str, Any]): The metadata to update
|
|
873
|
+
"""
|
|
874
|
+
try:
|
|
875
|
+
weaviate_client = self.get_client()
|
|
876
|
+
collection = weaviate_client.collections.get(self.collection)
|
|
877
|
+
|
|
878
|
+
# Query for objects with the given content_id
|
|
879
|
+
query_result = collection.query.fetch_objects( # type: ignore
|
|
880
|
+
where=Filter.by_property("content_id").equal(content_id),
|
|
881
|
+
limit=1000, # Get all matching objects
|
|
882
|
+
)
|
|
883
|
+
|
|
884
|
+
if not query_result.objects:
|
|
885
|
+
logger.debug(f"No documents found with content_id: {content_id}")
|
|
886
|
+
return
|
|
887
|
+
|
|
888
|
+
# Update each matching object
|
|
889
|
+
updated_count = 0
|
|
890
|
+
for obj in query_result.objects:
|
|
891
|
+
# Get current properties
|
|
892
|
+
current_properties = obj.properties or {}
|
|
893
|
+
|
|
894
|
+
# Merge existing metadata with new metadata
|
|
895
|
+
updated_properties = current_properties.copy()
|
|
896
|
+
|
|
897
|
+
# Handle nested metadata updates
|
|
898
|
+
if "meta_data" in updated_properties and isinstance(updated_properties["meta_data"], dict):
|
|
899
|
+
updated_properties["meta_data"].update(metadata)
|
|
900
|
+
else:
|
|
901
|
+
# If no existing meta_data or it's not a dict, set it directly
|
|
902
|
+
updated_properties["meta_data"] = metadata
|
|
903
|
+
|
|
904
|
+
if "filters" in updated_properties and isinstance(updated_properties["filters"], dict):
|
|
905
|
+
updated_properties["filters"].update(metadata)
|
|
906
|
+
else:
|
|
907
|
+
updated_properties["filters"] = metadata
|
|
908
|
+
|
|
909
|
+
# Update the object
|
|
910
|
+
collection.data.update(uuid=obj.uuid, properties=updated_properties)
|
|
911
|
+
updated_count += 1
|
|
912
|
+
|
|
913
|
+
logger.debug(f"Updated metadata for {updated_count} documents with content_id: {content_id}")
|
|
914
|
+
|
|
915
|
+
except Exception as e:
|
|
916
|
+
logger.error(f"Error updating metadata for content_id '{content_id}': {e}")
|
|
917
|
+
raise
|
|
918
|
+
|
|
919
|
+
def _delete_by_content_hash(self, content_hash: str) -> bool:
|
|
920
|
+
"""Delete documents by content hash using direct filter deletion."""
|
|
921
|
+
try:
|
|
922
|
+
collection = self.get_client().collections.get(self.collection)
|
|
923
|
+
|
|
924
|
+
# Build filter for content_hash search
|
|
925
|
+
filter_expr = Filter.by_property("content_hash").equal(content_hash)
|
|
926
|
+
|
|
927
|
+
collection.data.delete_many(where=filter_expr)
|
|
928
|
+
|
|
929
|
+
log_info(f"Deleted documents with content_hash '{content_hash}' from collection '{self.collection}'.")
|
|
930
|
+
return True
|
|
931
|
+
|
|
932
|
+
except Exception as e:
|
|
933
|
+
logger.error(f"Error deleting documents by content_hash '{content_hash}': {e}")
|
|
934
|
+
return False
|
agno/workflow/__init__.py
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
from agno.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
from agno.workflow.
|
|
1
|
+
from agno.workflow.condition import Condition
|
|
2
|
+
from agno.workflow.loop import Loop
|
|
3
|
+
from agno.workflow.parallel import Parallel
|
|
4
|
+
from agno.workflow.router import Router
|
|
5
|
+
from agno.workflow.step import Step
|
|
6
|
+
from agno.workflow.steps import Steps
|
|
7
|
+
from agno.workflow.types import StepInput, StepOutput, WorkflowExecutionInput
|
|
8
|
+
from agno.workflow.workflow import Workflow
|
|
8
9
|
|
|
9
10
|
__all__ = [
|
|
10
|
-
"RunEvent",
|
|
11
|
-
"RunResponse",
|
|
12
11
|
"Workflow",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
12
|
+
"Steps",
|
|
13
|
+
"Step",
|
|
14
|
+
"Loop",
|
|
15
|
+
"Parallel",
|
|
16
|
+
"Condition",
|
|
17
|
+
"Router",
|
|
18
|
+
"WorkflowExecutionInput",
|
|
19
|
+
"StepInput",
|
|
20
|
+
"StepOutput",
|
|
17
21
|
]
|