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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
from typing import Any, Dict, List, Optional
|
|
2
3
|
|
|
3
4
|
try:
|
|
@@ -8,9 +9,9 @@ except ImportError:
|
|
|
8
9
|
"The `upstash-vector` package is not installed, please install using `pip install upstash-vector`"
|
|
9
10
|
)
|
|
10
11
|
|
|
11
|
-
from agno.document import Document
|
|
12
|
-
from agno.embedder import Embedder
|
|
13
|
-
from agno.reranker.base import Reranker
|
|
12
|
+
from agno.knowledge.document import Document
|
|
13
|
+
from agno.knowledge.embedder import Embedder
|
|
14
|
+
from agno.knowledge.reranker.base import Reranker
|
|
14
15
|
from agno.utils.log import log_info, logger
|
|
15
16
|
from agno.vectordb.base import VectorDb
|
|
16
17
|
|
|
@@ -139,19 +140,52 @@ class UpstashVectorDb(VectorDb):
|
|
|
139
140
|
"""
|
|
140
141
|
return self.index.list_namespaces()
|
|
141
142
|
|
|
142
|
-
def
|
|
143
|
-
"""Check if
|
|
143
|
+
def content_hash_exists(self, content_hash: str) -> bool:
|
|
144
|
+
"""Check if documents with the given content hash exist in the index.
|
|
145
|
+
|
|
144
146
|
Args:
|
|
145
|
-
|
|
147
|
+
content_hash (str): The content hash to check.
|
|
148
|
+
|
|
146
149
|
Returns:
|
|
147
|
-
bool: True if the
|
|
150
|
+
bool: True if documents with the content hash exist, False otherwise.
|
|
148
151
|
"""
|
|
149
|
-
|
|
150
|
-
|
|
152
|
+
try:
|
|
153
|
+
# Use query with a filter to check if any documents exist with this content_hash
|
|
154
|
+
# We only need to check existence, so limit to 1 result
|
|
155
|
+
filter_str = f'content_hash = "{content_hash}"'
|
|
156
|
+
|
|
157
|
+
if not self.use_upstash_embeddings and self.embedder is not None:
|
|
158
|
+
# For custom embeddings, we need a dummy vector for the query
|
|
159
|
+
# Use a zero vector as we only care about the filter match
|
|
160
|
+
info = self.index.info()
|
|
161
|
+
dimension = info.dimension
|
|
162
|
+
dummy_vector = [0.0] * dimension
|
|
163
|
+
|
|
164
|
+
response = self.index.query(
|
|
165
|
+
vector=dummy_vector,
|
|
166
|
+
namespace=self.namespace,
|
|
167
|
+
top_k=1,
|
|
168
|
+
filter=filter_str,
|
|
169
|
+
include_data=False,
|
|
170
|
+
include_metadata=False,
|
|
171
|
+
include_vectors=False,
|
|
172
|
+
)
|
|
173
|
+
else:
|
|
174
|
+
# For hosted embeddings, use a minimal text query
|
|
175
|
+
response = self.index.query(
|
|
176
|
+
data="", # Empty query since we only care about the filter
|
|
177
|
+
namespace=self.namespace,
|
|
178
|
+
top_k=1,
|
|
179
|
+
filter=filter_str,
|
|
180
|
+
include_data=False,
|
|
181
|
+
include_metadata=False,
|
|
182
|
+
include_vectors=False,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
return response is not None and len(response) > 0
|
|
186
|
+
except Exception as e:
|
|
187
|
+
logger.error(f"Error checking if content_hash {content_hash} exists: {e}")
|
|
151
188
|
return False
|
|
152
|
-
documents_to_fetch = [document.id]
|
|
153
|
-
response = self.index.fetch(ids=documents_to_fetch)
|
|
154
|
-
return len(response) > 0
|
|
155
189
|
|
|
156
190
|
def name_exists(self, name: str) -> bool:
|
|
157
191
|
"""You can check if an index exists in Upstash Console.
|
|
@@ -177,7 +211,11 @@ class UpstashVectorDb(VectorDb):
|
|
|
177
211
|
return namespace in namespaces
|
|
178
212
|
|
|
179
213
|
def upsert(
|
|
180
|
-
self,
|
|
214
|
+
self,
|
|
215
|
+
content_hash: str,
|
|
216
|
+
documents: List[Document],
|
|
217
|
+
filters: Optional[Dict[str, Any]] = None,
|
|
218
|
+
namespace: Optional[str] = None,
|
|
181
219
|
) -> None:
|
|
182
220
|
"""Upsert documents into the index.
|
|
183
221
|
|
|
@@ -189,12 +227,38 @@ class UpstashVectorDb(VectorDb):
|
|
|
189
227
|
_namespace = self.namespace if namespace is None else namespace
|
|
190
228
|
vectors = []
|
|
191
229
|
|
|
192
|
-
for document in documents:
|
|
230
|
+
for i, document in enumerate(documents):
|
|
193
231
|
if document.id is None:
|
|
194
232
|
logger.error(f"Document ID must not be None. Skipping document: {document.content[:100]}...")
|
|
195
233
|
continue
|
|
196
234
|
|
|
197
|
-
|
|
235
|
+
logger.debug(
|
|
236
|
+
f"Processing document {i + 1}: ID={document.id}, name={document.name}, "
|
|
237
|
+
f"content_id={getattr(document, 'content_id', 'N/A')}"
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# Create a copy of metadata to avoid modifying the original document
|
|
241
|
+
meta_data = document.meta_data.copy() if document.meta_data else {}
|
|
242
|
+
|
|
243
|
+
# Add filters to document metadata if provided
|
|
244
|
+
if filters:
|
|
245
|
+
meta_data.update(filters)
|
|
246
|
+
|
|
247
|
+
meta_data["text"] = document.content
|
|
248
|
+
|
|
249
|
+
# Add content_id to metadata if it exists
|
|
250
|
+
if hasattr(document, "content_id") and document.content_id:
|
|
251
|
+
meta_data["content_id"] = document.content_id
|
|
252
|
+
else:
|
|
253
|
+
logger.warning(f"Document {document.id} has no content_id")
|
|
254
|
+
|
|
255
|
+
meta_data["content_hash"] = content_hash
|
|
256
|
+
|
|
257
|
+
# Add name to metadata if it exists
|
|
258
|
+
if document.name:
|
|
259
|
+
meta_data["name"] = document.name
|
|
260
|
+
else:
|
|
261
|
+
logger.warning(f"Document {document.id} has no name")
|
|
198
262
|
|
|
199
263
|
if not self.use_upstash_embeddings:
|
|
200
264
|
if self.embedder is None:
|
|
@@ -206,17 +270,16 @@ class UpstashVectorDb(VectorDb):
|
|
|
206
270
|
logger.error(f"Failed to generate embedding for document: {document.id}")
|
|
207
271
|
continue
|
|
208
272
|
|
|
209
|
-
vector = Vector(
|
|
210
|
-
id=document.id, vector=document.embedding, metadata=document.meta_data, data=document.content
|
|
211
|
-
)
|
|
273
|
+
vector = Vector(id=document.id, vector=document.embedding, metadata=meta_data, data=document.content)
|
|
212
274
|
else:
|
|
213
|
-
vector = Vector(id=document.id, data=document.content, metadata=
|
|
275
|
+
vector = Vector(id=document.id, data=document.content, metadata=meta_data)
|
|
214
276
|
vectors.append(vector)
|
|
215
277
|
|
|
216
278
|
if not vectors:
|
|
217
279
|
logger.warning("No valid documents to upsert")
|
|
218
280
|
return
|
|
219
281
|
|
|
282
|
+
logger.info(f"Upserting {len(vectors)} vectors to Upstash with IDs: {[v.id for v in vectors[:5]]}...")
|
|
220
283
|
self.index.upsert(vectors, namespace=_namespace)
|
|
221
284
|
|
|
222
285
|
def upsert_available(self) -> bool:
|
|
@@ -226,16 +289,15 @@ class UpstashVectorDb(VectorDb):
|
|
|
226
289
|
"""
|
|
227
290
|
return True
|
|
228
291
|
|
|
229
|
-
def insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
292
|
+
def insert(self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None:
|
|
230
293
|
"""Insert documents into the index.
|
|
231
294
|
This method is not supported by Upstash. Use `upsert` instead.
|
|
232
295
|
Args:
|
|
233
296
|
documents (List[Document]): The documents to insert.
|
|
234
297
|
filters (Optional[Dict[str, Any]], optional): The filters for the insert. Defaults to None.
|
|
235
|
-
Raises:
|
|
236
|
-
NotImplementedError: This method is not supported by Upstash.
|
|
237
298
|
"""
|
|
238
|
-
|
|
299
|
+
logger.warning("Upstash does not support insert operations. Using upsert instead.")
|
|
300
|
+
self.upsert(content_hash=content_hash, documents=documents, filters=filters)
|
|
239
301
|
|
|
240
302
|
def search(
|
|
241
303
|
self,
|
|
@@ -255,7 +317,7 @@ class UpstashVectorDb(VectorDb):
|
|
|
255
317
|
"""
|
|
256
318
|
_namespace = self.namespace if namespace is None else namespace
|
|
257
319
|
|
|
258
|
-
|
|
320
|
+
filter_str = "" if filters is None else str(filters)
|
|
259
321
|
|
|
260
322
|
if not self.use_upstash_embeddings and self.embedder is not None:
|
|
261
323
|
dense_embedding = self.embedder.get_embedding(query)
|
|
@@ -268,7 +330,7 @@ class UpstashVectorDb(VectorDb):
|
|
|
268
330
|
vector=dense_embedding,
|
|
269
331
|
namespace=_namespace,
|
|
270
332
|
top_k=limit,
|
|
271
|
-
|
|
333
|
+
filter=filter_str,
|
|
272
334
|
include_data=True,
|
|
273
335
|
include_metadata=True,
|
|
274
336
|
include_vectors=True,
|
|
@@ -278,7 +340,7 @@ class UpstashVectorDb(VectorDb):
|
|
|
278
340
|
data=query,
|
|
279
341
|
namespace=_namespace,
|
|
280
342
|
top_k=limit,
|
|
281
|
-
|
|
343
|
+
filter=filter_str,
|
|
282
344
|
include_data=True,
|
|
283
345
|
include_metadata=True,
|
|
284
346
|
include_vectors=True,
|
|
@@ -303,6 +365,7 @@ class UpstashVectorDb(VectorDb):
|
|
|
303
365
|
if self.reranker:
|
|
304
366
|
search_results = self.reranker.rerank(query=query, documents=search_results)
|
|
305
367
|
|
|
368
|
+
log_info(f"Found {len(search_results)} results")
|
|
306
369
|
return search_results
|
|
307
370
|
|
|
308
371
|
def delete(self, namespace: Optional[str] = None, delete_all: bool = False) -> bool:
|
|
@@ -330,5 +393,258 @@ class UpstashVectorDb(VectorDb):
|
|
|
330
393
|
"""
|
|
331
394
|
pass
|
|
332
395
|
|
|
396
|
+
def delete_by_id(self, id: str) -> bool:
|
|
397
|
+
"""Delete document by ID.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
id (str): The document ID to delete
|
|
401
|
+
|
|
402
|
+
Returns:
|
|
403
|
+
bool: True if deletion was successful, False otherwise
|
|
404
|
+
"""
|
|
405
|
+
try:
|
|
406
|
+
response = self.index.delete(ids=[id], namespace=self.namespace)
|
|
407
|
+
deleted_count = getattr(response, "deleted", 0)
|
|
408
|
+
logger.info(f"Deleted {deleted_count} document(s) with ID: {id}")
|
|
409
|
+
return True
|
|
410
|
+
except Exception as e:
|
|
411
|
+
logger.error(f"Error deleting document by ID {id}: {e}")
|
|
412
|
+
return False
|
|
413
|
+
|
|
414
|
+
def delete_by_name(self, name: str) -> bool:
|
|
415
|
+
"""Delete documents by name using metadata filter.
|
|
416
|
+
|
|
417
|
+
Args:
|
|
418
|
+
name (str): The document name to delete
|
|
419
|
+
|
|
420
|
+
Returns:
|
|
421
|
+
bool: True if deletion was successful, False otherwise
|
|
422
|
+
"""
|
|
423
|
+
try:
|
|
424
|
+
# Use Upstash's delete with metadata filter
|
|
425
|
+
response = self.index.delete(filter=f'name = "{name}"', namespace=self.namespace)
|
|
426
|
+
deleted_count = getattr(response, "deleted", 0)
|
|
427
|
+
logger.info(f"Deleted {deleted_count} document(s) with name: {name}")
|
|
428
|
+
return True
|
|
429
|
+
except Exception as e:
|
|
430
|
+
logger.error(f"Error deleting documents by name {name}: {e}")
|
|
431
|
+
return False
|
|
432
|
+
|
|
433
|
+
def delete_by_metadata(self, metadata: Dict[str, Any]) -> bool:
|
|
434
|
+
"""Delete documents by metadata filter.
|
|
435
|
+
|
|
436
|
+
Args:
|
|
437
|
+
metadata (Dict[str, Any]): Metadata criteria for deletion
|
|
438
|
+
|
|
439
|
+
Returns:
|
|
440
|
+
bool: True if deletion was successful, False otherwise
|
|
441
|
+
"""
|
|
442
|
+
try:
|
|
443
|
+
# Build filter string for Upstash metadata filtering
|
|
444
|
+
filter_parts = []
|
|
445
|
+
for key, value in metadata.items():
|
|
446
|
+
if isinstance(value, str):
|
|
447
|
+
filter_parts.append(f'{key} = "{value}"')
|
|
448
|
+
else:
|
|
449
|
+
filter_parts.append(f"{key} = {value}")
|
|
450
|
+
|
|
451
|
+
filter_str = " AND ".join(filter_parts)
|
|
452
|
+
|
|
453
|
+
response = self.index.delete(filter=filter_str, namespace=self.namespace)
|
|
454
|
+
deleted_count = getattr(response, "deleted", 0)
|
|
455
|
+
logger.info(f"Deleted {deleted_count} document(s) matching metadata: {metadata}")
|
|
456
|
+
return True
|
|
457
|
+
except Exception as e:
|
|
458
|
+
logger.error(f"Error deleting documents by metadata {metadata}: {e}")
|
|
459
|
+
return False
|
|
460
|
+
|
|
461
|
+
def delete_by_content_id(self, content_id: str) -> bool:
|
|
462
|
+
"""Delete documents by content_id.
|
|
463
|
+
|
|
464
|
+
Args:
|
|
465
|
+
content_id (str): The content ID to delete
|
|
466
|
+
|
|
467
|
+
Returns:
|
|
468
|
+
bool: True if deletion was successful, False otherwise
|
|
469
|
+
"""
|
|
470
|
+
return self.delete_by_metadata({"content_id": content_id})
|
|
471
|
+
|
|
472
|
+
async def async_insert(
|
|
473
|
+
self, content_hash: str, documents: List[Document], filters: Optional[Dict[str, Any]] = None
|
|
474
|
+
) -> None:
|
|
475
|
+
logger.warning("Upstash does not support async insert operations. Using upsert instead.")
|
|
476
|
+
await self.async_upsert(content_hash=content_hash, documents=documents, filters=filters)
|
|
477
|
+
|
|
478
|
+
async def async_exists(self) -> bool:
|
|
479
|
+
raise NotImplementedError(f"Async not supported on {self.__class__.__name__}.")
|
|
480
|
+
|
|
333
481
|
async def async_name_exists(self, name: str) -> bool:
|
|
334
482
|
raise NotImplementedError(f"Async not supported on {self.__class__.__name__}.")
|
|
483
|
+
|
|
484
|
+
async def async_create(self) -> None:
|
|
485
|
+
raise NotImplementedError(f"Async not supported on {self.__class__.__name__}.")
|
|
486
|
+
|
|
487
|
+
async def async_drop(self) -> None:
|
|
488
|
+
raise NotImplementedError(f"Async not supported on {self.__class__.__name__}.")
|
|
489
|
+
|
|
490
|
+
async def async_upsert(
|
|
491
|
+
self,
|
|
492
|
+
content_hash: str,
|
|
493
|
+
documents: List[Document],
|
|
494
|
+
filters: Optional[Dict[str, Any]] = None,
|
|
495
|
+
namespace: Optional[str] = None,
|
|
496
|
+
) -> None:
|
|
497
|
+
"""Async Upsert documents into the index.
|
|
498
|
+
|
|
499
|
+
Args:
|
|
500
|
+
documents (List[Document]): The documents to upsert.
|
|
501
|
+
filters (Optional[Dict[str, Any]], optional): The filters for the upsert. Defaults to None.
|
|
502
|
+
namespace (Optional[str], optional): The namespace for the documents. Defaults to None, which uses the instance namespace.
|
|
503
|
+
"""
|
|
504
|
+
_namespace = self.namespace if namespace is None else namespace
|
|
505
|
+
vectors = []
|
|
506
|
+
|
|
507
|
+
embed_tasks = [document.async_embed(embedder=self.embedder) for document in documents]
|
|
508
|
+
await asyncio.gather(*embed_tasks, return_exceptions=True)
|
|
509
|
+
|
|
510
|
+
for i, document in enumerate(documents):
|
|
511
|
+
if document.id is None:
|
|
512
|
+
logger.error(f"Document ID must not be None. Skipping document: {document.content[:100]}...")
|
|
513
|
+
continue
|
|
514
|
+
|
|
515
|
+
logger.debug(
|
|
516
|
+
f"Processing document {i + 1}: ID={document.id}, name={document.name}, "
|
|
517
|
+
f"content_id={getattr(document, 'content_id', 'N/A')}"
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
# Create a copy of metadata to avoid modifying the original document
|
|
521
|
+
meta_data = document.meta_data.copy() if document.meta_data else {}
|
|
522
|
+
|
|
523
|
+
# Add filters to document metadata if provided
|
|
524
|
+
if filters:
|
|
525
|
+
meta_data.update(filters)
|
|
526
|
+
|
|
527
|
+
meta_data["text"] = document.content
|
|
528
|
+
|
|
529
|
+
# Add content_id to metadata if it exists
|
|
530
|
+
if hasattr(document, "content_id") and document.content_id:
|
|
531
|
+
meta_data["content_id"] = document.content_id
|
|
532
|
+
else:
|
|
533
|
+
logger.warning(f"Document {document.id} has no content_id")
|
|
534
|
+
|
|
535
|
+
meta_data["content_hash"] = content_hash
|
|
536
|
+
|
|
537
|
+
# Add name to metadata if it exists
|
|
538
|
+
if document.name:
|
|
539
|
+
meta_data["name"] = document.name
|
|
540
|
+
else:
|
|
541
|
+
logger.warning(f"Document {document.id} has no name")
|
|
542
|
+
|
|
543
|
+
if not self.use_upstash_embeddings:
|
|
544
|
+
if self.embedder is None:
|
|
545
|
+
logger.error("Embedder is None but use_upstash_embeddings is False")
|
|
546
|
+
continue
|
|
547
|
+
|
|
548
|
+
if document.embedding is None:
|
|
549
|
+
logger.error(f"Failed to generate embedding for document: {document.id}")
|
|
550
|
+
continue
|
|
551
|
+
|
|
552
|
+
vector = Vector(id=document.id, vector=document.embedding, metadata=meta_data, data=document.content)
|
|
553
|
+
else:
|
|
554
|
+
vector = Vector(id=document.id, data=document.content, metadata=meta_data)
|
|
555
|
+
vectors.append(vector)
|
|
556
|
+
|
|
557
|
+
if not vectors:
|
|
558
|
+
logger.warning("No valid documents to upsert")
|
|
559
|
+
return
|
|
560
|
+
|
|
561
|
+
logger.info(f"Upserting {len(vectors)} vectors to Upstash with IDs: {[v.id for v in vectors[:5]]}...")
|
|
562
|
+
self.index.upsert(vectors, namespace=_namespace)
|
|
563
|
+
|
|
564
|
+
async def async_search(
|
|
565
|
+
self, query: str, limit: int = 5, filters: Optional[Dict[str, Any]] = None
|
|
566
|
+
) -> List[Document]:
|
|
567
|
+
raise NotImplementedError(f"Async not supported on {self.__class__.__name__}.")
|
|
568
|
+
|
|
569
|
+
def id_exists(self, id: str) -> bool:
|
|
570
|
+
"""Check if a document with the given ID exists in the index.
|
|
571
|
+
|
|
572
|
+
Args:
|
|
573
|
+
id (str): The document ID to check.
|
|
574
|
+
|
|
575
|
+
Returns:
|
|
576
|
+
bool: True if the document exists, False otherwise.
|
|
577
|
+
"""
|
|
578
|
+
try:
|
|
579
|
+
response = self.index.fetch(ids=[id], namespace=self.namespace)
|
|
580
|
+
return len(response) > 0
|
|
581
|
+
except Exception as e:
|
|
582
|
+
logger.error(f"Error checking if ID {id} exists: {e}")
|
|
583
|
+
return False
|
|
584
|
+
|
|
585
|
+
def _delete_by_content_hash(self, content_hash: str) -> bool:
|
|
586
|
+
"""Delete documents by content hash using metadata filter.
|
|
587
|
+
|
|
588
|
+
Args:
|
|
589
|
+
content_hash (str): The content hash to delete.
|
|
590
|
+
|
|
591
|
+
Returns:
|
|
592
|
+
bool: True if deletion was successful, False otherwise.
|
|
593
|
+
"""
|
|
594
|
+
try:
|
|
595
|
+
response = self.index.delete(filter=f'content_hash = "{content_hash}"', namespace=self.namespace)
|
|
596
|
+
deleted_count = getattr(response, "deleted", 0)
|
|
597
|
+
logger.info(f"Deleted {deleted_count} document(s) with content_hash: {content_hash}")
|
|
598
|
+
return True
|
|
599
|
+
except Exception as e:
|
|
600
|
+
logger.error(f"Error deleting documents by content_hash {content_hash}: {e}")
|
|
601
|
+
return False
|
|
602
|
+
|
|
603
|
+
def update_metadata(self, content_id: str, metadata: Dict[str, Any]) -> None:
|
|
604
|
+
"""
|
|
605
|
+
Update the metadata for documents with the given content_id.
|
|
606
|
+
|
|
607
|
+
Args:
|
|
608
|
+
content_id (str): The content ID to update
|
|
609
|
+
metadata (Dict[str, Any]): The metadata to update
|
|
610
|
+
"""
|
|
611
|
+
try:
|
|
612
|
+
# Query for vectors with the given content_id
|
|
613
|
+
query_response = self.index.query(
|
|
614
|
+
filter=f'content_id = "{content_id}"',
|
|
615
|
+
top_k=1000, # Get all matching vectors
|
|
616
|
+
include_metadata=True,
|
|
617
|
+
namespace=self.namespace,
|
|
618
|
+
)
|
|
619
|
+
|
|
620
|
+
if not query_response or not hasattr(query_response, "__iter__"):
|
|
621
|
+
logger.debug(f"No documents found with content_id: {content_id}")
|
|
622
|
+
return
|
|
623
|
+
|
|
624
|
+
# Update each matching vector
|
|
625
|
+
updated_count = 0
|
|
626
|
+
for result in query_response:
|
|
627
|
+
if hasattr(result, "id") and hasattr(result, "metadata"):
|
|
628
|
+
vector_id = result.id
|
|
629
|
+
current_metadata = result.metadata or {}
|
|
630
|
+
|
|
631
|
+
# Merge existing metadata with new metadata
|
|
632
|
+
updated_metadata = current_metadata.copy()
|
|
633
|
+
updated_metadata.update(metadata)
|
|
634
|
+
|
|
635
|
+
if "filters" not in updated_metadata:
|
|
636
|
+
updated_metadata["filters"] = {}
|
|
637
|
+
if isinstance(updated_metadata["filters"], dict):
|
|
638
|
+
updated_metadata["filters"].update(metadata)
|
|
639
|
+
else:
|
|
640
|
+
updated_metadata["filters"] = metadata
|
|
641
|
+
|
|
642
|
+
# Update the vector metadata
|
|
643
|
+
self.index.update(id=vector_id, metadata=updated_metadata, namespace=self.namespace)
|
|
644
|
+
updated_count += 1
|
|
645
|
+
|
|
646
|
+
logger.debug(f"Updated metadata for {updated_count} documents with content_id: {content_id}")
|
|
647
|
+
|
|
648
|
+
except Exception as e:
|
|
649
|
+
logger.error(f"Error updating metadata for content_id '{content_id}': {e}")
|
|
650
|
+
raise
|