agno 1.8.1__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 +2778 -4123
- 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/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/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 +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 +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 +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 +2961 -4253
- 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 +68 -17
- 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 +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 +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/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 +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 +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 +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 -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.0a1.dist-info}/WHEEL +0 -0
- {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
- {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/top_level.txt +0 -0
agno/memory/v2/db/postgres.py
DELETED
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
from typing import Any, Dict, List, Optional
|
|
2
|
-
|
|
3
|
-
try:
|
|
4
|
-
from sqlalchemy.dialects import postgresql
|
|
5
|
-
from sqlalchemy.engine import Engine, create_engine
|
|
6
|
-
from sqlalchemy.inspection import inspect
|
|
7
|
-
from sqlalchemy.orm import scoped_session, sessionmaker
|
|
8
|
-
from sqlalchemy.schema import Column, MetaData, Table
|
|
9
|
-
from sqlalchemy.sql.expression import delete, select, text
|
|
10
|
-
from sqlalchemy.types import DateTime, String
|
|
11
|
-
except ImportError:
|
|
12
|
-
raise ImportError("`sqlalchemy` not installed. Please install using `pip install sqlalchemy 'psycopg[binary]'`")
|
|
13
|
-
|
|
14
|
-
from agno.memory.v2.db.base import MemoryDb
|
|
15
|
-
from agno.memory.v2.db.schema import MemoryRow
|
|
16
|
-
from agno.utils.log import log_debug, log_info, logger
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class PostgresMemoryDb(MemoryDb):
|
|
20
|
-
def __init__(
|
|
21
|
-
self,
|
|
22
|
-
table_name: str,
|
|
23
|
-
schema: Optional[str] = "ai",
|
|
24
|
-
db_url: Optional[str] = None,
|
|
25
|
-
db_engine: Optional[Engine] = None,
|
|
26
|
-
):
|
|
27
|
-
"""
|
|
28
|
-
This class provides a memory store backed by a postgres table.
|
|
29
|
-
|
|
30
|
-
The following order is used to determine the database connection:
|
|
31
|
-
1. Use the db_engine if provided
|
|
32
|
-
2. Use the db_url to create the engine
|
|
33
|
-
|
|
34
|
-
Args:
|
|
35
|
-
table_name (str): The name of the table to store memory rows.
|
|
36
|
-
schema (Optional[str]): The schema to store the table in. Defaults to "ai".
|
|
37
|
-
db_url (Optional[str]): The database URL to connect to. Defaults to None.
|
|
38
|
-
db_engine (Optional[Engine]): The database engine to use. Defaults to None.
|
|
39
|
-
"""
|
|
40
|
-
_engine: Optional[Engine] = db_engine
|
|
41
|
-
if _engine is None and db_url is not None:
|
|
42
|
-
_engine = create_engine(db_url)
|
|
43
|
-
|
|
44
|
-
if _engine is None:
|
|
45
|
-
raise ValueError("Must provide either db_url or db_engine")
|
|
46
|
-
|
|
47
|
-
self.table_name: str = table_name
|
|
48
|
-
self.schema: Optional[str] = schema
|
|
49
|
-
self.db_url: Optional[str] = db_url
|
|
50
|
-
self.db_engine: Engine = _engine
|
|
51
|
-
self.inspector = inspect(self.db_engine)
|
|
52
|
-
self.metadata: MetaData = MetaData(schema=self.schema)
|
|
53
|
-
self.Session: scoped_session = scoped_session(sessionmaker(bind=self.db_engine))
|
|
54
|
-
self.table: Table = self.get_table()
|
|
55
|
-
|
|
56
|
-
def __dict__(self) -> Dict[str, Any]:
|
|
57
|
-
return {
|
|
58
|
-
"name": "PostgresMemoryDb",
|
|
59
|
-
"table_name": self.table_name,
|
|
60
|
-
"schema": self.schema,
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
def get_table(self) -> Table:
|
|
64
|
-
return Table(
|
|
65
|
-
self.table_name,
|
|
66
|
-
self.metadata,
|
|
67
|
-
Column("id", String, primary_key=True),
|
|
68
|
-
Column("user_id", String, index=True),
|
|
69
|
-
Column("memory", postgresql.JSONB, server_default=text("'{}'::jsonb")),
|
|
70
|
-
Column("created_at", DateTime(timezone=True), server_default=text("now()")),
|
|
71
|
-
Column("updated_at", DateTime(timezone=True), onupdate=text("now()")),
|
|
72
|
-
extend_existing=True,
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
def create(self) -> None:
|
|
76
|
-
if not self.table_exists():
|
|
77
|
-
try:
|
|
78
|
-
with self.Session() as sess, sess.begin():
|
|
79
|
-
if self.schema is not None:
|
|
80
|
-
log_debug(f"Creating schema: {self.schema}")
|
|
81
|
-
sess.execute(text(f"CREATE SCHEMA IF NOT EXISTS {self.schema};"))
|
|
82
|
-
log_debug(f"Creating table: {self.table_name}")
|
|
83
|
-
self.table.create(self.db_engine, checkfirst=True)
|
|
84
|
-
except Exception as e:
|
|
85
|
-
logger.error(f"Error creating table '{self.table.fullname}': {e}")
|
|
86
|
-
raise
|
|
87
|
-
|
|
88
|
-
def memory_exists(self, memory: MemoryRow) -> bool:
|
|
89
|
-
columns = [self.table.c.id]
|
|
90
|
-
with self.Session() as sess, sess.begin():
|
|
91
|
-
stmt = select(*columns).where(self.table.c.id == memory.id)
|
|
92
|
-
result = sess.execute(stmt).first()
|
|
93
|
-
return result is not None
|
|
94
|
-
|
|
95
|
-
def read_memories(
|
|
96
|
-
self, user_id: Optional[str] = None, limit: Optional[int] = None, sort: Optional[str] = None
|
|
97
|
-
) -> List[MemoryRow]:
|
|
98
|
-
memories: List[MemoryRow] = []
|
|
99
|
-
try:
|
|
100
|
-
with self.Session() as sess, sess.begin():
|
|
101
|
-
stmt = select(self.table)
|
|
102
|
-
if user_id is not None:
|
|
103
|
-
stmt = stmt.where(self.table.c.user_id == user_id)
|
|
104
|
-
if limit is not None:
|
|
105
|
-
stmt = stmt.limit(limit)
|
|
106
|
-
|
|
107
|
-
if sort == "asc":
|
|
108
|
-
stmt = stmt.order_by(self.table.c.created_at.asc())
|
|
109
|
-
else:
|
|
110
|
-
stmt = stmt.order_by(self.table.c.created_at.desc())
|
|
111
|
-
|
|
112
|
-
rows = sess.execute(stmt).fetchall()
|
|
113
|
-
for row in rows:
|
|
114
|
-
if row is not None:
|
|
115
|
-
memories.append(MemoryRow.model_validate(row))
|
|
116
|
-
except Exception as e:
|
|
117
|
-
log_debug(f"Exception reading from table: {e}")
|
|
118
|
-
log_debug(f"Table does not exist: {self.table.name}")
|
|
119
|
-
log_debug("Creating table for future transactions")
|
|
120
|
-
self.create()
|
|
121
|
-
return memories
|
|
122
|
-
|
|
123
|
-
def upsert_memory(self, memory: MemoryRow, create_and_retry: bool = True) -> None:
|
|
124
|
-
"""Create a new memory if it does not exist, otherwise update the existing memory"""
|
|
125
|
-
|
|
126
|
-
try:
|
|
127
|
-
with self.Session() as sess, sess.begin():
|
|
128
|
-
# Create an insert statement
|
|
129
|
-
stmt = postgresql.insert(self.table).values(
|
|
130
|
-
id=memory.id,
|
|
131
|
-
user_id=memory.user_id,
|
|
132
|
-
memory=memory.memory,
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
# Define the upsert if the memory already exists
|
|
136
|
-
# See: https://docs.sqlalchemy.org/en/20/dialects/postgresql.html#postgresql-insert-on-conflict
|
|
137
|
-
stmt = stmt.on_conflict_do_update(
|
|
138
|
-
index_elements=["id"],
|
|
139
|
-
set_=dict(
|
|
140
|
-
user_id=stmt.excluded.user_id,
|
|
141
|
-
memory=stmt.excluded.memory,
|
|
142
|
-
),
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
sess.execute(stmt)
|
|
146
|
-
except Exception as e:
|
|
147
|
-
log_debug(f"Exception upserting into table: {e}")
|
|
148
|
-
log_debug(f"Table does not exist: {self.table.name}")
|
|
149
|
-
log_debug("Creating table for future transactions")
|
|
150
|
-
self.create()
|
|
151
|
-
if create_and_retry:
|
|
152
|
-
return self.upsert_memory(memory, create_and_retry=False)
|
|
153
|
-
return None
|
|
154
|
-
|
|
155
|
-
def delete_memory(self, memory_id: str) -> None:
|
|
156
|
-
with self.Session() as sess, sess.begin():
|
|
157
|
-
stmt = delete(self.table).where(self.table.c.id == memory_id)
|
|
158
|
-
sess.execute(stmt)
|
|
159
|
-
|
|
160
|
-
def drop_table(self) -> None:
|
|
161
|
-
if self.table_exists():
|
|
162
|
-
log_debug(f"Deleting table: {self.table_name}")
|
|
163
|
-
self.table.drop(self.db_engine)
|
|
164
|
-
|
|
165
|
-
def table_exists(self) -> bool:
|
|
166
|
-
log_debug(f"Checking if table exists: {self.table.name}")
|
|
167
|
-
try:
|
|
168
|
-
return inspect(self.db_engine).has_table(self.table.name, schema=self.schema)
|
|
169
|
-
except Exception as e:
|
|
170
|
-
logger.error(e)
|
|
171
|
-
return False
|
|
172
|
-
|
|
173
|
-
def clear(self) -> bool:
|
|
174
|
-
if self.table_exists():
|
|
175
|
-
with self.Session() as sess, sess.begin():
|
|
176
|
-
stmt = delete(self.table)
|
|
177
|
-
log_info(f"Clearing table: {self.table.name}")
|
|
178
|
-
sess.execute(stmt)
|
|
179
|
-
return True
|
|
180
|
-
return False
|
|
181
|
-
|
|
182
|
-
def __deepcopy__(self, memo):
|
|
183
|
-
"""
|
|
184
|
-
Create a deep copy of the PgMemoryDb instance, handling unpickleable attributes.
|
|
185
|
-
|
|
186
|
-
Args:
|
|
187
|
-
memo (dict): A dictionary of objects already copied during the current copying pass.
|
|
188
|
-
|
|
189
|
-
Returns:
|
|
190
|
-
PostgresMemoryDb: A deep-copied instance of PgMemoryDb.
|
|
191
|
-
"""
|
|
192
|
-
from copy import deepcopy
|
|
193
|
-
|
|
194
|
-
# Create a new instance without calling __init__
|
|
195
|
-
cls = self.__class__
|
|
196
|
-
copied_obj = cls.__new__(cls)
|
|
197
|
-
memo[id(self)] = copied_obj
|
|
198
|
-
|
|
199
|
-
# Deep copy attributes
|
|
200
|
-
|
|
201
|
-
for k, v in self.__dict__().items():
|
|
202
|
-
if k in {"metadata", "table"}:
|
|
203
|
-
continue
|
|
204
|
-
# Reuse db_engine and Session without copying
|
|
205
|
-
elif k in {"db_engine", "Session"}:
|
|
206
|
-
setattr(copied_obj, k, v)
|
|
207
|
-
else:
|
|
208
|
-
setattr(copied_obj, k, deepcopy(v, memo))
|
|
209
|
-
|
|
210
|
-
# Recreate metadata and table for the copied instance
|
|
211
|
-
copied_obj.metadata = MetaData(schema=copied_obj.schema)
|
|
212
|
-
copied_obj.table = copied_obj.get_table()
|
|
213
|
-
|
|
214
|
-
return copied_obj
|
agno/memory/v2/db/redis.py
DELETED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import time
|
|
3
|
-
from typing import Any, Dict, List, Optional
|
|
4
|
-
|
|
5
|
-
try:
|
|
6
|
-
from redis import ConnectionError, Redis
|
|
7
|
-
except ImportError:
|
|
8
|
-
raise ImportError("`redis` not installed. Please install it using `pip install redis`")
|
|
9
|
-
|
|
10
|
-
from agno.memory.v2.db.base import MemoryDb
|
|
11
|
-
from agno.memory.v2.db.schema import MemoryRow
|
|
12
|
-
from agno.utils.log import log_debug, log_info, logger
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class RedisMemoryDb(MemoryDb):
|
|
16
|
-
def __init__(
|
|
17
|
-
self,
|
|
18
|
-
prefix: str = "agno_memory",
|
|
19
|
-
host: str = "localhost",
|
|
20
|
-
port: int = 6379,
|
|
21
|
-
db: int = 0,
|
|
22
|
-
password: Optional[str] = None,
|
|
23
|
-
ssl: Optional[bool] = False,
|
|
24
|
-
expire: Optional[int] = None,
|
|
25
|
-
):
|
|
26
|
-
"""
|
|
27
|
-
Initialize Redis memory store.
|
|
28
|
-
|
|
29
|
-
Args:
|
|
30
|
-
prefix (str): Prefix for Redis keys to namespace the memories
|
|
31
|
-
host (str): Redis host address
|
|
32
|
-
port (int): Redis port number
|
|
33
|
-
db (int): Redis database number
|
|
34
|
-
password (Optional[str]): Redis password if authentication is required
|
|
35
|
-
ssl (Optional[bool]): Whether to use SSL for Redis connection
|
|
36
|
-
expire (Optional[int]): TTL (time to live) in seconds for Redis keys. None means no expiration.
|
|
37
|
-
"""
|
|
38
|
-
self.prefix = prefix
|
|
39
|
-
self.expire = expire
|
|
40
|
-
self.redis_client = Redis(
|
|
41
|
-
host=host,
|
|
42
|
-
port=port,
|
|
43
|
-
db=db,
|
|
44
|
-
password=password,
|
|
45
|
-
decode_responses=True, # Automatically decode responses to str
|
|
46
|
-
ssl=ssl,
|
|
47
|
-
)
|
|
48
|
-
log_debug(f"Created RedisMemoryDb with prefix: '{self.prefix}'")
|
|
49
|
-
|
|
50
|
-
def __dict__(self) -> Dict[str, Any]:
|
|
51
|
-
return {
|
|
52
|
-
"name": "RedisMemoryDb",
|
|
53
|
-
"prefix": self.prefix,
|
|
54
|
-
"expire": self.expire,
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
def _get_key(self, memory_id: str) -> str:
|
|
58
|
-
"""Generate Redis key for a memory."""
|
|
59
|
-
return f"{self.prefix}:{memory_id}"
|
|
60
|
-
|
|
61
|
-
def create(self) -> None:
|
|
62
|
-
"""
|
|
63
|
-
Test connection to Redis.
|
|
64
|
-
For Redis, we don't need to create schema as it's schema-less.
|
|
65
|
-
"""
|
|
66
|
-
try:
|
|
67
|
-
self.redis_client.ping()
|
|
68
|
-
log_debug("Redis connection successful")
|
|
69
|
-
except ConnectionError as e:
|
|
70
|
-
logger.error(f"Could not connect to Redis: {e}")
|
|
71
|
-
raise
|
|
72
|
-
|
|
73
|
-
def memory_exists(self, memory: MemoryRow) -> bool:
|
|
74
|
-
"""Check if a memory exists"""
|
|
75
|
-
try:
|
|
76
|
-
key = self._get_key(memory.id) # type: ignore
|
|
77
|
-
return self.redis_client.exists(key) > 0 # type: ignore
|
|
78
|
-
except Exception as e:
|
|
79
|
-
logger.error(f"Error checking memory existence: {e}")
|
|
80
|
-
return False
|
|
81
|
-
|
|
82
|
-
def read_memories(
|
|
83
|
-
self, user_id: Optional[str] = None, limit: Optional[int] = None, sort: Optional[str] = None
|
|
84
|
-
) -> List[MemoryRow]:
|
|
85
|
-
"""Read memories from Redis"""
|
|
86
|
-
memories: List[MemoryRow] = []
|
|
87
|
-
try:
|
|
88
|
-
# Get all keys matching the prefix pattern
|
|
89
|
-
pattern = f"{self.prefix}:*"
|
|
90
|
-
memory_data = []
|
|
91
|
-
|
|
92
|
-
# Collect all matching memories
|
|
93
|
-
for key in self.redis_client.scan_iter(match=pattern):
|
|
94
|
-
data_str = self.redis_client.get(key)
|
|
95
|
-
if data_str:
|
|
96
|
-
data = json.loads(data_str) # type: ignore
|
|
97
|
-
|
|
98
|
-
# Filter by user_id if specified
|
|
99
|
-
if user_id is None or data.get("user_id") == user_id:
|
|
100
|
-
memory_data.append(data)
|
|
101
|
-
|
|
102
|
-
# Sort by created_at timestamp
|
|
103
|
-
if sort == "asc":
|
|
104
|
-
memory_data.sort(key=lambda x: x.get("created_at", 0))
|
|
105
|
-
else:
|
|
106
|
-
memory_data.sort(key=lambda x: x.get("created_at", 0), reverse=True)
|
|
107
|
-
|
|
108
|
-
# Apply limit if specified
|
|
109
|
-
if limit is not None and limit > 0:
|
|
110
|
-
memory_data = memory_data[:limit]
|
|
111
|
-
|
|
112
|
-
# Convert to MemoryRow objects
|
|
113
|
-
for data in memory_data:
|
|
114
|
-
memories.append(MemoryRow.model_validate(data))
|
|
115
|
-
|
|
116
|
-
except Exception as e:
|
|
117
|
-
logger.error(f"Error reading memories: {e}")
|
|
118
|
-
|
|
119
|
-
return memories
|
|
120
|
-
|
|
121
|
-
def upsert_memory(self, memory: MemoryRow) -> Optional[MemoryRow]:
|
|
122
|
-
"""Upsert a memory in Redis"""
|
|
123
|
-
try:
|
|
124
|
-
# Prepare data
|
|
125
|
-
timestamp = int(time.time())
|
|
126
|
-
|
|
127
|
-
# Convert to dict and handle datetime objects
|
|
128
|
-
memory_data = memory.model_dump(mode="json")
|
|
129
|
-
|
|
130
|
-
# Add timestamps if not present
|
|
131
|
-
if "created_at" not in memory_data:
|
|
132
|
-
memory_data["created_at"] = timestamp
|
|
133
|
-
|
|
134
|
-
memory_data["updated_at"] = timestamp
|
|
135
|
-
|
|
136
|
-
# Save to Redis
|
|
137
|
-
key = self._get_key(memory.id) # type: ignore
|
|
138
|
-
if self.expire is not None:
|
|
139
|
-
self.redis_client.set(key, json.dumps(memory_data), ex=self.expire)
|
|
140
|
-
else:
|
|
141
|
-
self.redis_client.set(key, json.dumps(memory_data))
|
|
142
|
-
|
|
143
|
-
return memory
|
|
144
|
-
|
|
145
|
-
except Exception as e:
|
|
146
|
-
logger.error(f"Error upserting memory: {e}")
|
|
147
|
-
return None
|
|
148
|
-
|
|
149
|
-
def delete_memory(self, memory_id: str) -> None:
|
|
150
|
-
"""Delete a memory from Redis"""
|
|
151
|
-
try:
|
|
152
|
-
key = self._get_key(memory_id)
|
|
153
|
-
self.redis_client.delete(key)
|
|
154
|
-
log_debug(f"Deleted memory: {memory_id}")
|
|
155
|
-
except Exception as e:
|
|
156
|
-
logger.error(f"Error deleting memory: {e}")
|
|
157
|
-
|
|
158
|
-
def drop_table(self) -> None:
|
|
159
|
-
"""Drop all memories from Redis (same as clear)"""
|
|
160
|
-
self.clear()
|
|
161
|
-
|
|
162
|
-
def table_exists(self) -> bool:
|
|
163
|
-
"""Check if any memories exist with our prefix"""
|
|
164
|
-
try:
|
|
165
|
-
pattern = f"{self.prefix}:*"
|
|
166
|
-
# Use scan_iter with count=1 to efficiently check if any keys exist
|
|
167
|
-
for _ in self.redis_client.scan_iter(match=pattern, count=1):
|
|
168
|
-
return True
|
|
169
|
-
return False
|
|
170
|
-
except Exception as e:
|
|
171
|
-
logger.error(f"Error checking if table exists: {e}")
|
|
172
|
-
return False
|
|
173
|
-
|
|
174
|
-
def clear(self) -> bool:
|
|
175
|
-
"""Clear all memories with our prefix"""
|
|
176
|
-
try:
|
|
177
|
-
pattern = f"{self.prefix}:*"
|
|
178
|
-
keys_to_delete = list(self.redis_client.scan_iter(match=pattern))
|
|
179
|
-
|
|
180
|
-
if keys_to_delete:
|
|
181
|
-
self.redis_client.delete(*keys_to_delete)
|
|
182
|
-
log_info(f"Cleared {len(keys_to_delete)} memories with prefix: {self.prefix}")
|
|
183
|
-
|
|
184
|
-
return True
|
|
185
|
-
except Exception as e:
|
|
186
|
-
logger.error(f"Error clearing memories: {e}")
|
|
187
|
-
return False
|
agno/memory/v2/db/schema.py
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
from typing import Any, Dict, Optional
|
|
3
|
-
|
|
4
|
-
from pydantic import BaseModel, ConfigDict, model_validator
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class MemoryRow(BaseModel):
|
|
8
|
-
"""Memory Row that is stored in the database"""
|
|
9
|
-
|
|
10
|
-
# id for this memory, auto-generated if not provided
|
|
11
|
-
id: Optional[str] = None
|
|
12
|
-
memory: Dict[str, Any]
|
|
13
|
-
user_id: Optional[str] = None
|
|
14
|
-
last_updated: Optional[datetime] = None
|
|
15
|
-
|
|
16
|
-
model_config = ConfigDict(from_attributes=True, arbitrary_types_allowed=True)
|
|
17
|
-
|
|
18
|
-
@model_validator(mode="after")
|
|
19
|
-
def generate_id(self) -> "MemoryRow":
|
|
20
|
-
if self.id is None:
|
|
21
|
-
from uuid import uuid4
|
|
22
|
-
|
|
23
|
-
self.id = str(uuid4())
|
|
24
|
-
return self
|
|
25
|
-
|
|
26
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
27
|
-
_dict = self.model_dump(exclude={"last_updated"})
|
|
28
|
-
_dict["last_updated"] = self.last_updated.isoformat() if self.last_updated else None
|
|
29
|
-
return _dict
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class SummaryRow(BaseModel):
|
|
33
|
-
"""Session Summary Row that is stored in the database"""
|
|
34
|
-
|
|
35
|
-
# id for this summary
|
|
36
|
-
id: Optional[str] = None
|
|
37
|
-
summary: Dict[str, Any]
|
|
38
|
-
user_id: Optional[str] = None
|
|
39
|
-
last_updated: Optional[datetime] = None
|
|
40
|
-
|
|
41
|
-
model_config = ConfigDict(from_attributes=True, arbitrary_types_allowed=True)
|
|
42
|
-
|
|
43
|
-
@model_validator(mode="after")
|
|
44
|
-
def generate_id(self) -> "SummaryRow":
|
|
45
|
-
if self.id is None:
|
|
46
|
-
from uuid import uuid4
|
|
47
|
-
|
|
48
|
-
self.id = str(uuid4())
|
|
49
|
-
return self
|
|
50
|
-
|
|
51
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
52
|
-
_dict = self.model_dump(exclude={"last_updated"})
|
|
53
|
-
_dict["last_updated"] = self.last_updated.isoformat() if self.last_updated else None
|
|
54
|
-
return _dict
|
agno/memory/v2/db/sqlite.py
DELETED
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
from typing import Any, Dict, List, Optional
|
|
3
|
-
|
|
4
|
-
try:
|
|
5
|
-
from sqlalchemy import (
|
|
6
|
-
Column,
|
|
7
|
-
DateTime,
|
|
8
|
-
Engine,
|
|
9
|
-
MetaData,
|
|
10
|
-
String,
|
|
11
|
-
Table,
|
|
12
|
-
create_engine,
|
|
13
|
-
delete,
|
|
14
|
-
inspect,
|
|
15
|
-
select,
|
|
16
|
-
text,
|
|
17
|
-
)
|
|
18
|
-
from sqlalchemy.exc import SQLAlchemyError
|
|
19
|
-
from sqlalchemy.orm import scoped_session, sessionmaker
|
|
20
|
-
except ImportError:
|
|
21
|
-
raise ImportError("`sqlalchemy` not installed. Please install it with `pip install sqlalchemy`")
|
|
22
|
-
|
|
23
|
-
from agno.memory.v2.db.base import MemoryDb
|
|
24
|
-
from agno.memory.v2.db.schema import MemoryRow
|
|
25
|
-
from agno.utils.log import log_debug, log_info, logger
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class SqliteMemoryDb(MemoryDb):
|
|
29
|
-
def __init__(
|
|
30
|
-
self,
|
|
31
|
-
table_name: str = "memory",
|
|
32
|
-
db_url: Optional[str] = None,
|
|
33
|
-
db_file: Optional[str] = None,
|
|
34
|
-
db_engine: Optional[Engine] = None,
|
|
35
|
-
):
|
|
36
|
-
"""
|
|
37
|
-
This class provides a memory store backed by a SQLite table.
|
|
38
|
-
|
|
39
|
-
The following order is used to determine the database connection:
|
|
40
|
-
1. Use the db_engine if provided
|
|
41
|
-
2. Use the db_url
|
|
42
|
-
3. Use the db_file
|
|
43
|
-
4. Create a new in-memory database
|
|
44
|
-
|
|
45
|
-
Args:
|
|
46
|
-
table_name: The name of the table to store Agent sessions.
|
|
47
|
-
db_url: The database URL to connect to.
|
|
48
|
-
db_file: The database file to connect to.
|
|
49
|
-
db_engine: The database engine to use.
|
|
50
|
-
"""
|
|
51
|
-
self.db_file = db_file
|
|
52
|
-
_engine: Optional[Engine] = db_engine
|
|
53
|
-
if _engine is None and db_url is not None:
|
|
54
|
-
_engine = create_engine(db_url)
|
|
55
|
-
elif _engine is None and db_file is not None:
|
|
56
|
-
# Use the db_file to create the engine
|
|
57
|
-
db_path = Path(db_file).resolve()
|
|
58
|
-
# Ensure the directory exists
|
|
59
|
-
db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
60
|
-
_engine = create_engine(f"sqlite:///{db_path}")
|
|
61
|
-
else:
|
|
62
|
-
_engine = create_engine("sqlite://")
|
|
63
|
-
|
|
64
|
-
if _engine is None:
|
|
65
|
-
raise ValueError("Must provide either db_url, db_file or db_engine")
|
|
66
|
-
|
|
67
|
-
# Database attributes
|
|
68
|
-
self.table_name: str = table_name
|
|
69
|
-
self.db_url: Optional[str] = db_url
|
|
70
|
-
self.db_engine: Engine = _engine
|
|
71
|
-
self.metadata: MetaData = MetaData()
|
|
72
|
-
self.inspector = inspect(self.db_engine)
|
|
73
|
-
|
|
74
|
-
# Database session
|
|
75
|
-
self.Session = scoped_session(sessionmaker(bind=self.db_engine))
|
|
76
|
-
# Database table for memories
|
|
77
|
-
self.table: Table = self.get_table()
|
|
78
|
-
|
|
79
|
-
def __dict__(self) -> Dict[str, Any]:
|
|
80
|
-
return {
|
|
81
|
-
"name": "SqliteMemoryDb",
|
|
82
|
-
"table_name": self.table_name,
|
|
83
|
-
"db_file": self.db_file,
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
def get_table(self) -> Table:
|
|
87
|
-
return Table(
|
|
88
|
-
self.table_name,
|
|
89
|
-
self.metadata,
|
|
90
|
-
Column("id", String, primary_key=True),
|
|
91
|
-
Column("user_id", String, index=True),
|
|
92
|
-
Column("memory", String),
|
|
93
|
-
Column("created_at", DateTime, server_default=text("CURRENT_TIMESTAMP")),
|
|
94
|
-
Column(
|
|
95
|
-
"updated_at", DateTime, server_default=text("CURRENT_TIMESTAMP"), onupdate=text("CURRENT_TIMESTAMP")
|
|
96
|
-
),
|
|
97
|
-
extend_existing=True,
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
def create(self) -> None:
|
|
101
|
-
if not self.table_exists():
|
|
102
|
-
try:
|
|
103
|
-
log_debug(f"Creating table: {self.table_name}")
|
|
104
|
-
self.table.create(self.db_engine, checkfirst=True)
|
|
105
|
-
except Exception as e:
|
|
106
|
-
logger.error(f"Error creating table '{self.table_name}': {e}")
|
|
107
|
-
raise
|
|
108
|
-
|
|
109
|
-
def memory_exists(self, memory: MemoryRow) -> bool:
|
|
110
|
-
with self.Session() as session:
|
|
111
|
-
stmt = select(self.table.c.id).where(self.table.c.id == memory.id)
|
|
112
|
-
result = session.execute(stmt).first()
|
|
113
|
-
return result is not None
|
|
114
|
-
|
|
115
|
-
def read_memories(
|
|
116
|
-
self, user_id: Optional[str] = None, limit: Optional[int] = None, sort: Optional[str] = None
|
|
117
|
-
) -> List[MemoryRow]:
|
|
118
|
-
memories: List[MemoryRow] = []
|
|
119
|
-
try:
|
|
120
|
-
with self.Session() as session:
|
|
121
|
-
stmt = select(self.table)
|
|
122
|
-
if user_id is not None:
|
|
123
|
-
stmt = stmt.where(self.table.c.user_id == user_id)
|
|
124
|
-
|
|
125
|
-
if sort == "asc":
|
|
126
|
-
stmt = stmt.order_by(self.table.c.created_at.asc())
|
|
127
|
-
else:
|
|
128
|
-
stmt = stmt.order_by(self.table.c.created_at.desc())
|
|
129
|
-
|
|
130
|
-
if limit is not None:
|
|
131
|
-
stmt = stmt.limit(limit)
|
|
132
|
-
|
|
133
|
-
result = session.execute(stmt)
|
|
134
|
-
for row in result:
|
|
135
|
-
memories.append(
|
|
136
|
-
MemoryRow(
|
|
137
|
-
id=row.id,
|
|
138
|
-
user_id=row.user_id,
|
|
139
|
-
memory=eval(row.memory),
|
|
140
|
-
last_updated=row.updated_at or row.created_at,
|
|
141
|
-
)
|
|
142
|
-
)
|
|
143
|
-
except SQLAlchemyError as e:
|
|
144
|
-
log_debug(f"Exception reading from table: {e}")
|
|
145
|
-
log_debug(f"Table does not exist: {self.table_name}")
|
|
146
|
-
log_debug("Creating table for future transactions")
|
|
147
|
-
self.create()
|
|
148
|
-
return memories
|
|
149
|
-
|
|
150
|
-
def upsert_memory(self, memory: MemoryRow, create_and_retry: bool = True) -> None:
|
|
151
|
-
try:
|
|
152
|
-
with self.Session() as session:
|
|
153
|
-
# Check if the memory already exists
|
|
154
|
-
existing = session.execute(select(self.table).where(self.table.c.id == memory.id)).first()
|
|
155
|
-
|
|
156
|
-
if existing:
|
|
157
|
-
# Update existing memory
|
|
158
|
-
stmt = (
|
|
159
|
-
self.table.update()
|
|
160
|
-
.where(self.table.c.id == memory.id)
|
|
161
|
-
.values(user_id=memory.user_id, memory=str(memory.memory), updated_at=text("CURRENT_TIMESTAMP"))
|
|
162
|
-
)
|
|
163
|
-
else:
|
|
164
|
-
# Insert new memory
|
|
165
|
-
stmt = self.table.insert().values(id=memory.id, user_id=memory.user_id, memory=str(memory.memory)) # type: ignore
|
|
166
|
-
|
|
167
|
-
session.execute(stmt)
|
|
168
|
-
session.commit()
|
|
169
|
-
except SQLAlchemyError as e:
|
|
170
|
-
logger.error(f"Exception upserting into table: {e}")
|
|
171
|
-
if not self.table_exists():
|
|
172
|
-
log_info(f"Table does not exist: {self.table_name}")
|
|
173
|
-
log_info("Creating table for future transactions")
|
|
174
|
-
self.create()
|
|
175
|
-
if create_and_retry:
|
|
176
|
-
return self.upsert_memory(memory, create_and_retry=False)
|
|
177
|
-
else:
|
|
178
|
-
raise
|
|
179
|
-
|
|
180
|
-
def delete_memory(self, memory_id: str) -> None:
|
|
181
|
-
with self.Session() as session:
|
|
182
|
-
stmt = delete(self.table).where(self.table.c.id == memory_id)
|
|
183
|
-
session.execute(stmt)
|
|
184
|
-
session.commit()
|
|
185
|
-
|
|
186
|
-
def drop_table(self) -> None:
|
|
187
|
-
if self.table_exists():
|
|
188
|
-
log_debug(f"Deleting table: {self.table_name}")
|
|
189
|
-
self.table.drop(self.db_engine)
|
|
190
|
-
|
|
191
|
-
def table_exists(self) -> bool:
|
|
192
|
-
log_debug(f"Checking if table exists: {self.table.name}")
|
|
193
|
-
try:
|
|
194
|
-
return self.inspector.has_table(self.table.name)
|
|
195
|
-
except Exception as e:
|
|
196
|
-
logger.error(e)
|
|
197
|
-
return False
|
|
198
|
-
|
|
199
|
-
def clear(self) -> bool:
|
|
200
|
-
with self.Session() as session:
|
|
201
|
-
if self.table_exists():
|
|
202
|
-
stmt = delete(self.table)
|
|
203
|
-
session.execute(stmt)
|
|
204
|
-
session.commit()
|
|
205
|
-
return True
|
|
206
|
-
|
|
207
|
-
def __del__(self):
|
|
208
|
-
# self.Session.remove()
|
|
209
|
-
pass
|