agno 1.8.2__py3-none-any.whl → 2.0.0__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/agent/__init__.py +19 -27
- agno/agent/agent.py +3143 -4170
- 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 +1416 -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 +154 -48
- 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 +1551 -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 +47 -65
- agno/knowledge/reader/docx_reader.py +83 -0
- agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
- agno/{document → knowledge}/reader/json_reader.py +30 -9
- agno/{document → knowledge}/reader/markdown_reader.py +58 -9
- agno/{document → knowledge}/reader/pdf_reader.py +71 -126
- agno/knowledge/reader/reader_factory.py +268 -0
- agno/knowledge/reader/s3_reader.py +101 -0
- agno/{document → knowledge}/reader/text_reader.py +31 -10
- agno/knowledge/reader/url_reader.py +128 -0
- agno/knowledge/reader/web_search_reader.py +366 -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 +269 -268
- 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 +128 -72
- 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 +346 -290
- agno/models/cerebras/cerebras.py +84 -27
- agno/models/cohere/chat.py +106 -98
- agno/models/google/gemini.py +105 -46
- 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 +46 -151
- 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 +85 -47
- agno/models/openai/chat.py +154 -37
- 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 +15 -9
- 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 +497 -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 +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 +235 -0
- agno/os/router.py +1400 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +393 -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 +850 -0
- agno/os/routers/knowledge/schemas.py +118 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +410 -0
- agno/os/routers/memory/schemas.py +58 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +178 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +536 -0
- agno/os/schema.py +945 -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/agent.py +633 -0
- agno/run/base.py +53 -77
- agno/run/cancel.py +81 -0
- agno/run/team.py +243 -96
- agno/run/workflow.py +550 -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 +3260 -4824
- 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 +43 -23
- agno/tools/browserbase.py +13 -4
- agno/tools/calcom.py +12 -10
- agno/tools/calculator.py +10 -27
- agno/tools/cartesia.py +20 -17
- 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 +22 -12
- agno/tools/daytona.py +13 -16
- agno/tools/decorator.py +6 -3
- agno/tools/desi_vocal.py +17 -8
- 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 +36 -29
- agno/tools/email.py +4 -1
- agno/tools/evm.py +7 -1
- agno/tools/exa.py +19 -14
- agno/tools/fal.py +30 -30
- agno/tools/file.py +9 -8
- agno/tools/financial_datasets.py +25 -44
- agno/tools/firecrawl.py +17 -18
- agno/tools/function.py +127 -18
- agno/tools/giphy.py +23 -11
- 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 +18 -33
- agno/tools/linkup.py +5 -1
- agno/tools/local_file_system.py +8 -5
- agno/tools/lumalab.py +32 -20
- agno/tools/mcp.py +1 -2
- 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 +33 -15
- agno/tools/models/gemini.py +59 -32
- agno/tools/models/groq.py +30 -23
- agno/tools/models/nebius.py +28 -12
- agno/tools/models_labs.py +40 -16
- 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 +58 -32
- agno/tools/openbb.py +12 -11
- agno/tools/opencv.py +63 -47
- 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 +55 -42
- 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 +100 -123
- agno/utils/gemini.py +1 -1
- agno/utils/knowledge.py +29 -0
- agno/utils/log.py +54 -4
- agno/utils/mcp.py +68 -10
- agno/utils/media.py +39 -0
- agno/utils/message.py +12 -1
- agno/utils/models/aws_claude.py +1 -1
- agno/utils/models/claude.py +6 -12
- agno/utils/models/cohere.py +1 -1
- agno/utils/models/mistral.py +8 -7
- agno/utils/models/schema_utils.py +3 -3
- agno/utils/models/watsonx.py +1 -1
- agno/utils/openai.py +1 -1
- agno/utils/pprint.py +33 -32
- agno/utils/print_response/agent.py +779 -0
- agno/utils/print_response/team.py +1669 -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 +481 -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} +207 -49
- agno/workflow/{v2/steps.py → steps.py} +147 -66
- agno/workflow/types.py +482 -0
- agno/workflow/workflow.py +2410 -696
- agno-2.0.0.dist-info/METADATA +494 -0
- agno-2.0.0.dist-info/RECORD +515 -0
- agno-2.0.0.dist-info/licenses/LICENSE +201 -0
- agno/agent/metrics.py +0 -110
- 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 -1053
- agno/app/playground/deploy.py +0 -249
- agno/app/playground/operator.py +0 -183
- agno/app/playground/schemas.py +0 -223
- agno/app/playground/serve.py +0 -55
- agno/app/playground/sync_router.py +0 -1045
- 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/response.py +0 -467
- 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 -3313
- 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.2.dist-info/METADATA +0 -982
- agno-1.8.2.dist-info/RECORD +0 -566
- agno-1.8.2.dist-info/entry_points.txt +0 -3
- agno-1.8.2.dist-info/licenses/LICENSE +0 -375
- /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.2.dist-info → agno-2.0.0.dist-info}/WHEEL +0 -0
- {agno-1.8.2.dist-info → agno-2.0.0.dist-info}/top_level.txt +0 -0
agno/memory/v2/db/firestore.py
DELETED
|
@@ -1,339 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from datetime import datetime, timezone
|
|
3
|
-
from typing import Any, Dict, List, Optional
|
|
4
|
-
|
|
5
|
-
from agno.memory.v2.db.base import MemoryDb
|
|
6
|
-
from agno.memory.v2.db.schema import MemoryRow
|
|
7
|
-
from agno.utils.log import log_debug, logger
|
|
8
|
-
|
|
9
|
-
try:
|
|
10
|
-
from google.api_core import exceptions as google_exceptions
|
|
11
|
-
from google.cloud.firestore_v1 import (
|
|
12
|
-
Client,
|
|
13
|
-
CollectionReference,
|
|
14
|
-
DocumentReference,
|
|
15
|
-
Query,
|
|
16
|
-
Transaction,
|
|
17
|
-
transactional,
|
|
18
|
-
)
|
|
19
|
-
except ImportError:
|
|
20
|
-
raise ImportError(
|
|
21
|
-
"`google-cloud-firestore` not installed. Please install it using `pip install google-cloud-firestore`"
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class FirestoreMemoryDb(MemoryDb):
|
|
26
|
-
def __init__(
|
|
27
|
-
self,
|
|
28
|
-
collection_name: str = "memory",
|
|
29
|
-
db_name: Optional[str] = "(default)",
|
|
30
|
-
client: Optional[Client] = None,
|
|
31
|
-
project_id: Optional[str] = None,
|
|
32
|
-
):
|
|
33
|
-
"""
|
|
34
|
-
This class provides a memory store backed by a Firestore collection.
|
|
35
|
-
|
|
36
|
-
Args:
|
|
37
|
-
collection_name: The name of the collection to store memories
|
|
38
|
-
db_name: Name of the Firestore database (Default is "(default)" for free tier)
|
|
39
|
-
client: Optional existing Firestore client
|
|
40
|
-
project_id: Optional name of the GCP project to use
|
|
41
|
-
"""
|
|
42
|
-
self.collection_name = collection_name
|
|
43
|
-
self.db_name = db_name
|
|
44
|
-
self.project_id = project_id or os.getenv("GOOGLE_CLOUD_PROJECT")
|
|
45
|
-
|
|
46
|
-
# Initialize Firestore client
|
|
47
|
-
self._client = client
|
|
48
|
-
if self._client is None:
|
|
49
|
-
self._client = self._initialize_client()
|
|
50
|
-
|
|
51
|
-
# Get root collection reference
|
|
52
|
-
self.collection: CollectionReference = self._client.collection(self.collection_name)
|
|
53
|
-
|
|
54
|
-
# Store user_id for delete operations due to the data structure
|
|
55
|
-
self._user_id: Optional[str] = None
|
|
56
|
-
|
|
57
|
-
log_debug(f"Created FirestoreMemoryDb with collection: '{self.collection_name}'")
|
|
58
|
-
|
|
59
|
-
def _initialize_client(self) -> Client:
|
|
60
|
-
"""Initialize and return a Firestore client with proper error handling."""
|
|
61
|
-
try:
|
|
62
|
-
client = Client(database=self.db_name, project=self.project_id)
|
|
63
|
-
# Test the connection by listing collections
|
|
64
|
-
list(client.collections())
|
|
65
|
-
log_debug(f"Firestore client initialized with database: '{self.db_name}'")
|
|
66
|
-
return client
|
|
67
|
-
except google_exceptions.Unauthenticated as e:
|
|
68
|
-
logger.error(
|
|
69
|
-
"Firestore authentication failed. Please ensure you have proper Google Cloud credentials set up."
|
|
70
|
-
)
|
|
71
|
-
logger.error("Run 'gcloud auth application-default login' or set GOOGLE_APPLICATION_CREDENTIALS")
|
|
72
|
-
raise ImportError(
|
|
73
|
-
"Failed to authenticate with Google Cloud. Please set up authentication:\n"
|
|
74
|
-
"1. Run: gcloud auth application-default login\n"
|
|
75
|
-
"2. Or set GOOGLE_APPLICATION_CREDENTIALS environment variable"
|
|
76
|
-
) from e
|
|
77
|
-
except google_exceptions.PermissionDenied as e:
|
|
78
|
-
logger.error(
|
|
79
|
-
"Permission denied. Please ensure your service account has the necessary Firestore permissions."
|
|
80
|
-
)
|
|
81
|
-
raise ImportError(
|
|
82
|
-
"Permission denied when accessing Firestore. Please ensure:\n"
|
|
83
|
-
"1. Your service account has the 'Cloud Datastore User' role\n"
|
|
84
|
-
"2. The Firestore API is enabled for your project"
|
|
85
|
-
) from e
|
|
86
|
-
except google_exceptions.InvalidArgument as e:
|
|
87
|
-
if "database" in str(e).lower():
|
|
88
|
-
logger.error(f"Invalid database name '{self.db_name}'. Use '(default)' for the default database.")
|
|
89
|
-
raise ImportError(
|
|
90
|
-
f"Invalid database name '{self.db_name}'. For free tier, use '(default)' as the database name."
|
|
91
|
-
) from e
|
|
92
|
-
else:
|
|
93
|
-
logger.error(f"Invalid argument when initializing Firestore: {e}")
|
|
94
|
-
raise
|
|
95
|
-
except Exception as e:
|
|
96
|
-
logger.error(f"Failed to initialize Firestore client: {e}")
|
|
97
|
-
raise
|
|
98
|
-
|
|
99
|
-
def get_user_collection(self, user_id: str) -> CollectionReference:
|
|
100
|
-
"""Get the user-specific collection for storing memories."""
|
|
101
|
-
if self._client is None:
|
|
102
|
-
raise RuntimeError("Firestore client is not initialized")
|
|
103
|
-
return self._client.collection(f"{self.collection_name}/{user_id}/memories")
|
|
104
|
-
|
|
105
|
-
def _delete_document(self, document: DocumentReference) -> None:
|
|
106
|
-
"""Recursively delete a document and all its subcollections."""
|
|
107
|
-
log_debug(f"Deleting document: {document.path}")
|
|
108
|
-
for collection in document.collections():
|
|
109
|
-
self._delete_collection(collection)
|
|
110
|
-
document.delete()
|
|
111
|
-
|
|
112
|
-
def _delete_collection(self, collection: CollectionReference) -> None:
|
|
113
|
-
"""Recursively delete all documents in a collection."""
|
|
114
|
-
for document in collection.list_documents():
|
|
115
|
-
self._delete_document(document)
|
|
116
|
-
|
|
117
|
-
def create(self) -> None:
|
|
118
|
-
"""
|
|
119
|
-
Create the collection index.
|
|
120
|
-
For Firestore using user/memory model, this is a no-op to avoid index creation.
|
|
121
|
-
"""
|
|
122
|
-
try:
|
|
123
|
-
# Test connection
|
|
124
|
-
if self._client:
|
|
125
|
-
list(self._client.collections())
|
|
126
|
-
log_debug("Firestore connection successful")
|
|
127
|
-
except Exception as e:
|
|
128
|
-
logger.error(f"Could not connect to Firestore: {e}")
|
|
129
|
-
raise
|
|
130
|
-
|
|
131
|
-
def memory_exists(self, memory: MemoryRow) -> bool:
|
|
132
|
-
"""Check if a memory exists."""
|
|
133
|
-
try:
|
|
134
|
-
log_debug(f"Checking if memory exists: {memory.id}")
|
|
135
|
-
# Save user_id for potential future operations
|
|
136
|
-
self._user_id = memory.user_id
|
|
137
|
-
|
|
138
|
-
# Check in the user-specific collection
|
|
139
|
-
if memory.user_id is None:
|
|
140
|
-
# Return False when no user_id is provided (internal Memory v2 operations)
|
|
141
|
-
return False
|
|
142
|
-
|
|
143
|
-
user_collection = self.get_user_collection(memory.user_id)
|
|
144
|
-
doc = user_collection.document(memory.id).get()
|
|
145
|
-
return doc.exists
|
|
146
|
-
except Exception as e:
|
|
147
|
-
logger.error(f"Error checking memory existence: {e}")
|
|
148
|
-
return False
|
|
149
|
-
|
|
150
|
-
def read_memories(
|
|
151
|
-
self, user_id: Optional[str] = None, limit: Optional[int] = None, sort: Optional[str] = None
|
|
152
|
-
) -> List[MemoryRow]:
|
|
153
|
-
"""
|
|
154
|
-
Read memories from the collection.
|
|
155
|
-
|
|
156
|
-
Args:
|
|
157
|
-
user_id: ID of the user to read
|
|
158
|
-
limit: Maximum number of memories to read
|
|
159
|
-
sort: Sort order ("asc" or "desc")
|
|
160
|
-
|
|
161
|
-
Returns:
|
|
162
|
-
List[MemoryRow]: List of memories
|
|
163
|
-
"""
|
|
164
|
-
memories: List[MemoryRow] = []
|
|
165
|
-
|
|
166
|
-
if user_id is None:
|
|
167
|
-
return memories
|
|
168
|
-
|
|
169
|
-
try:
|
|
170
|
-
# Save user_id for potential future operations
|
|
171
|
-
self._user_id = user_id
|
|
172
|
-
|
|
173
|
-
# Get user-specific collection
|
|
174
|
-
user_collection = self.get_user_collection(user_id)
|
|
175
|
-
|
|
176
|
-
# Build query with ordering
|
|
177
|
-
query = user_collection.order_by(
|
|
178
|
-
"created_at",
|
|
179
|
-
direction=(Query.ASCENDING if sort == "asc" else Query.DESCENDING),
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
# Apply limit if specified
|
|
183
|
-
if limit is not None:
|
|
184
|
-
query = query.limit(limit)
|
|
185
|
-
|
|
186
|
-
# Execute query and build results
|
|
187
|
-
for doc in query.stream():
|
|
188
|
-
data = doc.to_dict()
|
|
189
|
-
if data is None:
|
|
190
|
-
continue
|
|
191
|
-
|
|
192
|
-
# Get timestamps for last_updated
|
|
193
|
-
updated_at = data.get("updated_at")
|
|
194
|
-
created_at = data.get("created_at")
|
|
195
|
-
last_updated = None
|
|
196
|
-
if updated_at:
|
|
197
|
-
last_updated = datetime.fromtimestamp(updated_at, tz=timezone.utc)
|
|
198
|
-
elif created_at:
|
|
199
|
-
last_updated = datetime.fromtimestamp(created_at, tz=timezone.utc)
|
|
200
|
-
|
|
201
|
-
memories.append(
|
|
202
|
-
MemoryRow(
|
|
203
|
-
id=data.get("id"),
|
|
204
|
-
user_id=data.get("user_id", user_id),
|
|
205
|
-
memory=data.get("memory", {}),
|
|
206
|
-
last_updated=last_updated,
|
|
207
|
-
)
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
return memories
|
|
211
|
-
except Exception as e:
|
|
212
|
-
logger.error(f"Error reading memories: {e}")
|
|
213
|
-
return []
|
|
214
|
-
|
|
215
|
-
def upsert_memory(self, memory: MemoryRow) -> None:
|
|
216
|
-
"""
|
|
217
|
-
Upsert a memory into the user-specific collection.
|
|
218
|
-
|
|
219
|
-
Args:
|
|
220
|
-
memory: MemoryRow to upsert
|
|
221
|
-
|
|
222
|
-
Returns:
|
|
223
|
-
None
|
|
224
|
-
"""
|
|
225
|
-
try:
|
|
226
|
-
log_debug(f"Upserting memory: {memory.id} for user: {memory.user_id}")
|
|
227
|
-
|
|
228
|
-
# Save user_id for potential future operations
|
|
229
|
-
self._user_id = memory.user_id
|
|
230
|
-
|
|
231
|
-
# Prepare timestamp
|
|
232
|
-
now = datetime.now(timezone.utc)
|
|
233
|
-
timestamp = int(now.timestamp())
|
|
234
|
-
|
|
235
|
-
# Get user-specific collection and document reference
|
|
236
|
-
if memory.user_id is None:
|
|
237
|
-
# Skip upsert when no user_id is provided (internal Memory v2 operations)
|
|
238
|
-
return
|
|
239
|
-
|
|
240
|
-
user_collection = self.get_user_collection(memory.user_id)
|
|
241
|
-
doc_ref = user_collection.document(memory.id)
|
|
242
|
-
|
|
243
|
-
# Prepare memory data with version for optimistic locking
|
|
244
|
-
memory_dict = memory.model_dump()
|
|
245
|
-
if "_version" not in memory_dict:
|
|
246
|
-
memory_dict["_version"] = 1
|
|
247
|
-
else:
|
|
248
|
-
memory_dict["_version"] += 1
|
|
249
|
-
|
|
250
|
-
# Build update data - include all fields
|
|
251
|
-
update_data: Dict[str, Any] = {
|
|
252
|
-
"id": memory.id,
|
|
253
|
-
"user_id": memory.user_id,
|
|
254
|
-
"memory": memory.memory,
|
|
255
|
-
"updated_at": timestamp,
|
|
256
|
-
"_version": memory_dict["_version"],
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
# Check if document exists to set created_at
|
|
260
|
-
doc = doc_ref.get()
|
|
261
|
-
if not doc.exists:
|
|
262
|
-
update_data["created_at"] = timestamp
|
|
263
|
-
else:
|
|
264
|
-
# Preserve existing created_at
|
|
265
|
-
existing_data = doc.to_dict()
|
|
266
|
-
if existing_data and "created_at" in existing_data:
|
|
267
|
-
update_data["created_at"] = existing_data["created_at"]
|
|
268
|
-
|
|
269
|
-
# Use a transaction for atomic update
|
|
270
|
-
if self._client is None:
|
|
271
|
-
raise RuntimeError("Firestore client is not initialized")
|
|
272
|
-
|
|
273
|
-
transaction = self._client.transaction()
|
|
274
|
-
|
|
275
|
-
@transactional
|
|
276
|
-
def update_in_transaction(transaction: Transaction) -> None:
|
|
277
|
-
# Re-read within transaction to ensure consistency
|
|
278
|
-
_ = doc_ref.get(transaction=transaction) # Read for consistency check
|
|
279
|
-
transaction.set(doc_ref, update_data)
|
|
280
|
-
|
|
281
|
-
# Execute the transaction
|
|
282
|
-
update_in_transaction(transaction)
|
|
283
|
-
|
|
284
|
-
except Exception as e:
|
|
285
|
-
logger.error(f"Error upserting memory: {e}")
|
|
286
|
-
raise
|
|
287
|
-
|
|
288
|
-
def delete_memory(self, memory_id: str) -> None:
|
|
289
|
-
"""
|
|
290
|
-
Delete a memory from the collection.
|
|
291
|
-
|
|
292
|
-
Args:
|
|
293
|
-
memory_id: ID of the memory to delete
|
|
294
|
-
"""
|
|
295
|
-
try:
|
|
296
|
-
log_debug(f"Deleting memory with id: {memory_id}")
|
|
297
|
-
|
|
298
|
-
if self._user_id:
|
|
299
|
-
user_collection = self.get_user_collection(self._user_id)
|
|
300
|
-
user_collection.document(memory_id).delete()
|
|
301
|
-
log_debug(f"Successfully deleted memory with id: {memory_id}")
|
|
302
|
-
else:
|
|
303
|
-
# Skip deletion when no user_id is available
|
|
304
|
-
pass
|
|
305
|
-
|
|
306
|
-
except Exception as e:
|
|
307
|
-
logger.error(f"Error deleting memory: {e}")
|
|
308
|
-
raise
|
|
309
|
-
|
|
310
|
-
def clear(self) -> bool:
|
|
311
|
-
"""Clear all memories from the collection."""
|
|
312
|
-
try:
|
|
313
|
-
for doc in self.collection.list_documents():
|
|
314
|
-
self._delete_document(doc)
|
|
315
|
-
log_debug(f"Cleared all memories in collection: {self.collection_name}")
|
|
316
|
-
return True
|
|
317
|
-
except Exception as e:
|
|
318
|
-
logger.error(f"Error clearing collection: {e}")
|
|
319
|
-
return False
|
|
320
|
-
|
|
321
|
-
def drop_table(self) -> None:
|
|
322
|
-
"""Drop the collection."""
|
|
323
|
-
try:
|
|
324
|
-
for doc in self.collection.list_documents():
|
|
325
|
-
self._delete_document(doc)
|
|
326
|
-
log_debug(f"Dropped collection: {self.collection_name}")
|
|
327
|
-
except Exception as e:
|
|
328
|
-
logger.error(f"Error dropping collection: {e}")
|
|
329
|
-
raise
|
|
330
|
-
|
|
331
|
-
def table_exists(self) -> bool:
|
|
332
|
-
"""Check if the collection exists."""
|
|
333
|
-
try:
|
|
334
|
-
# Try to stream one document to check if collection exists
|
|
335
|
-
_ = list(self.collection.limit(1).stream())
|
|
336
|
-
return True
|
|
337
|
-
except Exception as e:
|
|
338
|
-
logger.error(f"Error checking collection existence: {e}")
|
|
339
|
-
return False
|
agno/memory/v2/db/mongodb.py
DELETED
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
from datetime import datetime, timezone
|
|
2
|
-
from typing import Any, Dict, List, Optional
|
|
3
|
-
|
|
4
|
-
try:
|
|
5
|
-
from pymongo import MongoClient
|
|
6
|
-
from pymongo.collection import Collection
|
|
7
|
-
from pymongo.database import Database
|
|
8
|
-
from pymongo.errors import PyMongoError
|
|
9
|
-
except ImportError:
|
|
10
|
-
raise ImportError("`pymongo` not installed. Please install it with `pip install pymongo`")
|
|
11
|
-
|
|
12
|
-
from agno.memory.v2.db import MemoryDb
|
|
13
|
-
from agno.memory.v2.db.schema import MemoryRow
|
|
14
|
-
from agno.utils.log import log_debug, logger
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class MongoMemoryDb(MemoryDb):
|
|
18
|
-
def __init__(
|
|
19
|
-
self,
|
|
20
|
-
collection_name: str = "memory",
|
|
21
|
-
db_url: Optional[str] = None,
|
|
22
|
-
db_name: str = "agno",
|
|
23
|
-
client: Optional[MongoClient] = None,
|
|
24
|
-
):
|
|
25
|
-
"""
|
|
26
|
-
This class provides a memory store backed by a MongoDB collection.
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
collection_name: The name of the collection to store memories
|
|
30
|
-
db_url: MongoDB connection URL
|
|
31
|
-
db_name: Name of the database
|
|
32
|
-
client: Optional existing MongoDB client
|
|
33
|
-
"""
|
|
34
|
-
self._client: Optional[MongoClient] = client
|
|
35
|
-
if self._client is None and db_url is not None:
|
|
36
|
-
self._client = MongoClient(db_url)
|
|
37
|
-
|
|
38
|
-
if self._client is None:
|
|
39
|
-
raise ValueError("Must provide either db_url or client")
|
|
40
|
-
|
|
41
|
-
self.collection_name: str = collection_name
|
|
42
|
-
self.db_name: str = db_name
|
|
43
|
-
self.db: Database = self._client[self.db_name]
|
|
44
|
-
self.collection: Collection = self.db[self.collection_name]
|
|
45
|
-
|
|
46
|
-
def __dict__(self) -> Dict[str, Any]:
|
|
47
|
-
return {
|
|
48
|
-
"name": "MongoMemoryDb",
|
|
49
|
-
"collection_name": self.collection_name,
|
|
50
|
-
"db_name": self.db_name,
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
def create(self) -> None:
|
|
54
|
-
"""Create indexes for the collection"""
|
|
55
|
-
try:
|
|
56
|
-
# Create indexes
|
|
57
|
-
self.collection.create_index("id", unique=True)
|
|
58
|
-
self.collection.create_index("user_id")
|
|
59
|
-
self.collection.create_index("created_at")
|
|
60
|
-
except PyMongoError as e:
|
|
61
|
-
logger.error(f"Error creating indexes for collection '{self.collection_name}': {e}")
|
|
62
|
-
raise
|
|
63
|
-
|
|
64
|
-
def memory_exists(self, memory: MemoryRow) -> bool:
|
|
65
|
-
"""Check if a memory exists
|
|
66
|
-
Args:
|
|
67
|
-
memory: MemoryRow to check
|
|
68
|
-
Returns:
|
|
69
|
-
bool: True if the memory exists, False otherwise
|
|
70
|
-
"""
|
|
71
|
-
try:
|
|
72
|
-
result = self.collection.find_one({"id": memory.id})
|
|
73
|
-
return result is not None
|
|
74
|
-
except PyMongoError as e:
|
|
75
|
-
logger.error(f"Error checking memory existence: {e}")
|
|
76
|
-
return False
|
|
77
|
-
|
|
78
|
-
def read_memories(
|
|
79
|
-
self, user_id: Optional[str] = None, limit: Optional[int] = None, sort: Optional[str] = None
|
|
80
|
-
) -> List[MemoryRow]:
|
|
81
|
-
"""Read memories from the collection
|
|
82
|
-
Args:
|
|
83
|
-
user_id: ID of the user to read
|
|
84
|
-
limit: Maximum number of memories to read
|
|
85
|
-
sort: Sort order ("asc" or "desc")
|
|
86
|
-
Returns:
|
|
87
|
-
List[MemoryRow]: List of memories
|
|
88
|
-
"""
|
|
89
|
-
memories: List[MemoryRow] = []
|
|
90
|
-
try:
|
|
91
|
-
# Build query
|
|
92
|
-
query = {}
|
|
93
|
-
if user_id is not None:
|
|
94
|
-
query["user_id"] = user_id
|
|
95
|
-
|
|
96
|
-
# Build sort order
|
|
97
|
-
sort_order = -1 if sort != "asc" else 1
|
|
98
|
-
cursor = self.collection.find(query).sort("created_at", sort_order)
|
|
99
|
-
|
|
100
|
-
if limit is not None:
|
|
101
|
-
cursor = cursor.limit(limit)
|
|
102
|
-
|
|
103
|
-
for doc in cursor:
|
|
104
|
-
# Remove MongoDB _id before converting to MemoryRow
|
|
105
|
-
doc.pop("_id", None)
|
|
106
|
-
memories.append(MemoryRow(user_id=doc["user_id"], memory=doc["memory"]))
|
|
107
|
-
except PyMongoError as e:
|
|
108
|
-
logger.error(f"Error reading memories: {e}")
|
|
109
|
-
return memories
|
|
110
|
-
|
|
111
|
-
def upsert_memory(self, memory: MemoryRow, create_and_retry: bool = True) -> None:
|
|
112
|
-
"""Upsert a memory into the collection
|
|
113
|
-
Args:
|
|
114
|
-
memory: MemoryRow to upsert
|
|
115
|
-
create_and_retry: Whether to create a new memory if the id already exists
|
|
116
|
-
Returns:
|
|
117
|
-
None
|
|
118
|
-
"""
|
|
119
|
-
try:
|
|
120
|
-
now = datetime.now(timezone.utc)
|
|
121
|
-
timestamp = int(now.timestamp())
|
|
122
|
-
|
|
123
|
-
# Add version field for optimistic locking
|
|
124
|
-
memory_dict = memory.model_dump()
|
|
125
|
-
if "_version" not in memory_dict:
|
|
126
|
-
memory_dict["_version"] = 1
|
|
127
|
-
else:
|
|
128
|
-
memory_dict["_version"] += 1
|
|
129
|
-
|
|
130
|
-
update_data = {
|
|
131
|
-
"user_id": memory.user_id,
|
|
132
|
-
"memory": memory.memory,
|
|
133
|
-
"updated_at": timestamp,
|
|
134
|
-
"_version": memory_dict["_version"],
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
# For new documents, set created_at
|
|
138
|
-
query = {"id": memory.id}
|
|
139
|
-
doc = self.collection.find_one(query)
|
|
140
|
-
if not doc:
|
|
141
|
-
update_data["created_at"] = timestamp
|
|
142
|
-
|
|
143
|
-
result = self.collection.update_one(query, {"$set": update_data}, upsert=True)
|
|
144
|
-
|
|
145
|
-
if not result.acknowledged:
|
|
146
|
-
logger.error("Memory upsert not acknowledged")
|
|
147
|
-
|
|
148
|
-
except PyMongoError as e:
|
|
149
|
-
logger.error(f"Error upserting memory: {e}")
|
|
150
|
-
raise
|
|
151
|
-
|
|
152
|
-
def delete_memory(self, memory_id: str) -> None:
|
|
153
|
-
"""Delete a memory from the collection
|
|
154
|
-
Args:
|
|
155
|
-
id: ID of the memory to delete
|
|
156
|
-
Returns:
|
|
157
|
-
None
|
|
158
|
-
"""
|
|
159
|
-
try:
|
|
160
|
-
result = self.collection.delete_one({"id": memory_id})
|
|
161
|
-
if result.deleted_count == 0:
|
|
162
|
-
log_debug(f"No memory found with id: {memory_id}")
|
|
163
|
-
else:
|
|
164
|
-
log_debug(f"Successfully deleted memory with id: {memory_id}")
|
|
165
|
-
except PyMongoError as e:
|
|
166
|
-
logger.error(f"Error deleting memory: {e}")
|
|
167
|
-
raise
|
|
168
|
-
|
|
169
|
-
def drop_table(self) -> None:
|
|
170
|
-
"""Drop the collection
|
|
171
|
-
Returns:
|
|
172
|
-
None
|
|
173
|
-
"""
|
|
174
|
-
try:
|
|
175
|
-
self.collection.drop()
|
|
176
|
-
except PyMongoError as e:
|
|
177
|
-
logger.error(f"Error dropping collection: {e}")
|
|
178
|
-
|
|
179
|
-
def table_exists(self) -> bool:
|
|
180
|
-
"""Check if the collection exists
|
|
181
|
-
Returns:
|
|
182
|
-
bool: True if the collection exists, False otherwise
|
|
183
|
-
"""
|
|
184
|
-
return self.collection_name in self.db.list_collection_names()
|
|
185
|
-
|
|
186
|
-
def clear(self) -> bool:
|
|
187
|
-
"""Clear the collection
|
|
188
|
-
Returns:
|
|
189
|
-
bool: True if the collection was cleared, False otherwise
|
|
190
|
-
"""
|
|
191
|
-
try:
|
|
192
|
-
result = self.collection.delete_many({})
|
|
193
|
-
return result.acknowledged
|
|
194
|
-
except PyMongoError as e:
|
|
195
|
-
logger.error(f"Error clearing collection: {e}")
|
|
196
|
-
return False
|