agno 0.1.2__py3-none-any.whl → 2.3.13__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 +44 -5
- agno/agent/agent.py +10531 -2975
- agno/api/agent.py +14 -53
- agno/api/api.py +7 -46
- agno/api/evals.py +22 -0
- agno/api/os.py +17 -0
- agno/api/routes.py +6 -25
- agno/api/schemas/__init__.py +9 -0
- agno/api/schemas/agent.py +6 -9
- agno/api/schemas/evals.py +16 -0
- agno/api/schemas/os.py +14 -0
- agno/api/schemas/team.py +10 -10
- agno/api/schemas/utils.py +21 -0
- agno/api/schemas/workflows.py +16 -0
- agno/api/settings.py +53 -0
- agno/api/team.py +22 -26
- 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/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/__init__.py +24 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +946 -0
- agno/db/dynamo/__init__.py +3 -0
- agno/db/dynamo/dynamo.py +2781 -0
- agno/db/dynamo/schemas.py +442 -0
- agno/db/dynamo/utils.py +743 -0
- agno/db/firestore/__init__.py +3 -0
- agno/db/firestore/firestore.py +2379 -0
- agno/db/firestore/schemas.py +181 -0
- agno/db/firestore/utils.py +376 -0
- agno/db/gcs_json/__init__.py +3 -0
- agno/db/gcs_json/gcs_json_db.py +1791 -0
- agno/db/gcs_json/utils.py +228 -0
- agno/db/in_memory/__init__.py +3 -0
- agno/db/in_memory/in_memory_db.py +1312 -0
- agno/db/in_memory/utils.py +230 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1777 -0
- agno/db/json/utils.py +230 -0
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +635 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +17 -0
- agno/db/mongo/async_mongo.py +2760 -0
- agno/db/mongo/mongo.py +2597 -0
- agno/db/mongo/schemas.py +119 -0
- agno/db/mongo/utils.py +276 -0
- agno/db/mysql/__init__.py +4 -0
- agno/db/mysql/async_mysql.py +2912 -0
- agno/db/mysql/mysql.py +2923 -0
- agno/db/mysql/schemas.py +186 -0
- agno/db/mysql/utils.py +488 -0
- agno/db/postgres/__init__.py +4 -0
- agno/db/postgres/async_postgres.py +2579 -0
- agno/db/postgres/postgres.py +2870 -0
- agno/db/postgres/schemas.py +187 -0
- agno/db/postgres/utils.py +442 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +2141 -0
- agno/db/redis/schemas.py +159 -0
- agno/db/redis/utils.py +346 -0
- agno/db/schemas/__init__.py +4 -0
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/evals.py +34 -0
- agno/db/schemas/knowledge.py +40 -0
- agno/db/schemas/memory.py +61 -0
- agno/db/singlestore/__init__.py +3 -0
- agno/db/singlestore/schemas.py +179 -0
- agno/db/singlestore/singlestore.py +2877 -0
- agno/db/singlestore/utils.py +384 -0
- agno/db/sqlite/__init__.py +4 -0
- agno/db/sqlite/async_sqlite.py +2911 -0
- agno/db/sqlite/schemas.py +181 -0
- agno/db/sqlite/sqlite.py +2908 -0
- agno/db/sqlite/utils.py +429 -0
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +334 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1908 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +118 -0
- agno/eval/__init__.py +24 -0
- agno/eval/accuracy.py +666 -276
- agno/eval/agent_as_judge.py +861 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +779 -0
- agno/eval/reliability.py +241 -62
- agno/eval/utils.py +120 -0
- agno/exceptions.py +143 -1
- agno/filters.py +354 -0
- agno/guardrails/__init__.py +6 -0
- agno/guardrails/base.py +19 -0
- agno/guardrails/openai.py +144 -0
- agno/guardrails/pii.py +94 -0
- agno/guardrails/prompt_injection.py +52 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/__init__.py +3 -0
- agno/integrations/discord/client.py +203 -0
- agno/knowledge/__init__.py +5 -1
- agno/{document → knowledge}/chunking/agentic.py +22 -14
- agno/{document → knowledge}/chunking/document.py +2 -2
- agno/{document → knowledge}/chunking/fixed.py +7 -6
- agno/knowledge/chunking/markdown.py +151 -0
- agno/{document → knowledge}/chunking/recursive.py +15 -3
- agno/knowledge/chunking/row.py +39 -0
- agno/knowledge/chunking/semantic.py +91 -0
- agno/knowledge/chunking/strategy.py +165 -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/knowledge/embedder/aws_bedrock.py +343 -0
- agno/knowledge/embedder/azure_openai.py +210 -0
- agno/{embedder → knowledge/embedder}/base.py +8 -0
- agno/knowledge/embedder/cohere.py +323 -0
- agno/knowledge/embedder/fastembed.py +62 -0
- agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
- agno/knowledge/embedder/google.py +258 -0
- agno/knowledge/embedder/huggingface.py +94 -0
- agno/knowledge/embedder/jina.py +182 -0
- agno/knowledge/embedder/langdb.py +22 -0
- agno/knowledge/embedder/mistral.py +206 -0
- agno/knowledge/embedder/nebius.py +13 -0
- agno/knowledge/embedder/ollama.py +154 -0
- agno/knowledge/embedder/openai.py +195 -0
- agno/knowledge/embedder/sentence_transformer.py +63 -0
- agno/{embedder → knowledge/embedder}/together.py +1 -1
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +165 -0
- agno/knowledge/knowledge.py +3006 -0
- agno/knowledge/reader/__init__.py +7 -0
- agno/knowledge/reader/arxiv_reader.py +81 -0
- agno/knowledge/reader/base.py +95 -0
- agno/knowledge/reader/csv_reader.py +164 -0
- agno/knowledge/reader/docx_reader.py +82 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/firecrawl_reader.py +201 -0
- agno/knowledge/reader/json_reader.py +88 -0
- agno/knowledge/reader/markdown_reader.py +137 -0
- agno/knowledge/reader/pdf_reader.py +431 -0
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +313 -0
- agno/knowledge/reader/s3_reader.py +89 -0
- agno/knowledge/reader/tavily_reader.py +193 -0
- agno/knowledge/reader/text_reader.py +127 -0
- agno/knowledge/reader/web_search_reader.py +325 -0
- agno/knowledge/reader/website_reader.py +455 -0
- agno/knowledge/reader/wikipedia_reader.py +91 -0
- agno/knowledge/reader/youtube_reader.py +78 -0
- agno/knowledge/remote_content/remote_content.py +88 -0
- agno/knowledge/reranker/__init__.py +3 -0
- agno/{reranker → knowledge/reranker}/base.py +1 -1
- agno/{reranker → knowledge/reranker}/cohere.py +2 -2
- agno/knowledge/reranker/infinity.py +195 -0
- agno/knowledge/reranker/sentence_transformer.py +54 -0
- agno/knowledge/types.py +39 -0
- agno/knowledge/utils.py +234 -0
- agno/media.py +439 -95
- agno/memory/__init__.py +16 -3
- agno/memory/manager.py +1474 -123
- agno/memory/strategies/__init__.py +15 -0
- agno/memory/strategies/base.py +66 -0
- agno/memory/strategies/summarize.py +196 -0
- agno/memory/strategies/types.py +37 -0
- agno/models/aimlapi/__init__.py +5 -0
- agno/models/aimlapi/aimlapi.py +62 -0
- agno/models/anthropic/__init__.py +4 -0
- agno/models/anthropic/claude.py +960 -496
- agno/models/aws/__init__.py +15 -0
- agno/models/aws/bedrock.py +686 -451
- agno/models/aws/claude.py +190 -183
- agno/models/azure/__init__.py +18 -1
- agno/models/azure/ai_foundry.py +489 -0
- agno/models/azure/openai_chat.py +89 -40
- agno/models/base.py +2477 -550
- agno/models/cerebras/__init__.py +12 -0
- agno/models/cerebras/cerebras.py +565 -0
- agno/models/cerebras/cerebras_openai.py +131 -0
- agno/models/cohere/__init__.py +4 -0
- agno/models/cohere/chat.py +306 -492
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +74 -0
- agno/models/dashscope/__init__.py +5 -0
- agno/models/dashscope/dashscope.py +90 -0
- agno/models/deepinfra/__init__.py +5 -0
- agno/models/deepinfra/deepinfra.py +45 -0
- agno/models/deepseek/__init__.py +4 -0
- agno/models/deepseek/deepseek.py +110 -9
- agno/models/fireworks/__init__.py +4 -0
- agno/models/fireworks/fireworks.py +19 -22
- agno/models/google/__init__.py +3 -7
- agno/models/google/gemini.py +1717 -662
- agno/models/google/utils.py +22 -0
- agno/models/groq/__init__.py +4 -0
- agno/models/groq/groq.py +391 -666
- agno/models/huggingface/__init__.py +4 -0
- agno/models/huggingface/huggingface.py +266 -538
- agno/models/ibm/__init__.py +5 -0
- agno/models/ibm/watsonx.py +432 -0
- agno/models/internlm/__init__.py +3 -0
- agno/models/internlm/internlm.py +20 -3
- agno/models/langdb/__init__.py +1 -0
- agno/models/langdb/langdb.py +60 -0
- agno/models/litellm/__init__.py +14 -0
- agno/models/litellm/chat.py +503 -0
- agno/models/litellm/litellm_openai.py +42 -0
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/lmstudio/__init__.py +5 -0
- agno/models/lmstudio/lmstudio.py +25 -0
- agno/models/message.py +361 -39
- agno/models/meta/__init__.py +12 -0
- agno/models/meta/llama.py +502 -0
- agno/models/meta/llama_openai.py +79 -0
- agno/models/metrics.py +120 -0
- agno/models/mistral/__init__.py +4 -0
- agno/models/mistral/mistral.py +293 -393
- agno/models/nebius/__init__.py +3 -0
- agno/models/nebius/nebius.py +53 -0
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/__init__.py +4 -0
- agno/models/nvidia/nvidia.py +22 -3
- agno/models/ollama/__init__.py +4 -2
- agno/models/ollama/chat.py +257 -492
- agno/models/openai/__init__.py +7 -0
- agno/models/openai/chat.py +725 -770
- agno/models/openai/like.py +16 -2
- agno/models/openai/responses.py +1121 -0
- agno/models/openrouter/__init__.py +4 -0
- agno/models/openrouter/openrouter.py +62 -5
- agno/models/perplexity/__init__.py +5 -0
- agno/models/perplexity/perplexity.py +203 -0
- agno/models/portkey/__init__.py +3 -0
- agno/models/portkey/portkey.py +82 -0
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +69 -0
- agno/models/response.py +177 -7
- agno/models/sambanova/__init__.py +4 -0
- agno/models/sambanova/sambanova.py +23 -4
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +42 -0
- agno/models/together/__init__.py +4 -0
- agno/models/together/together.py +21 -164
- agno/models/utils.py +266 -0
- agno/models/vercel/__init__.py +3 -0
- agno/models/vercel/v0.py +43 -0
- agno/models/vertexai/__init__.py +0 -1
- agno/models/vertexai/claude.py +190 -0
- agno/models/vllm/__init__.py +3 -0
- agno/models/vllm/vllm.py +83 -0
- agno/models/xai/__init__.py +2 -0
- agno/models/xai/xai.py +111 -7
- agno/os/__init__.py +3 -0
- agno/os/app.py +1027 -0
- agno/os/auth.py +244 -0
- agno/os/config.py +126 -0
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/a2a/__init__.py +3 -0
- agno/os/interfaces/a2a/a2a.py +42 -0
- agno/os/interfaces/a2a/router.py +249 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/__init__.py +3 -0
- agno/os/interfaces/agui/agui.py +47 -0
- agno/os/interfaces/agui/router.py +147 -0
- agno/os/interfaces/agui/utils.py +574 -0
- agno/os/interfaces/base.py +25 -0
- agno/os/interfaces/slack/__init__.py +3 -0
- agno/os/interfaces/slack/router.py +148 -0
- agno/os/interfaces/slack/security.py +30 -0
- agno/os/interfaces/slack/slack.py +47 -0
- agno/os/interfaces/whatsapp/__init__.py +3 -0
- agno/os/interfaces/whatsapp/router.py +210 -0
- agno/os/interfaces/whatsapp/security.py +55 -0
- agno/os/interfaces/whatsapp/whatsapp.py +36 -0
- agno/os/mcp.py +293 -0
- agno/os/middleware/__init__.py +9 -0
- agno/os/middleware/jwt.py +797 -0
- agno/os/router.py +258 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +599 -0
- agno/os/routers/agents/schema.py +261 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +450 -0
- agno/os/routers/evals/schemas.py +174 -0
- agno/os/routers/evals/utils.py +231 -0
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/__init__.py +3 -0
- agno/os/routers/knowledge/knowledge.py +1008 -0
- agno/os/routers/knowledge/schemas.py +178 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +661 -0
- agno/os/routers/memory/schemas.py +88 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +190 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +997 -0
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +512 -0
- agno/os/routers/teams/schema.py +257 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +499 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +624 -0
- agno/os/routers/workflows/schema.py +75 -0
- agno/os/schema.py +534 -0
- agno/os/scopes.py +469 -0
- agno/{playground → os}/settings.py +7 -15
- agno/os/utils.py +973 -0
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +67 -0
- agno/reasoning/deepseek.py +63 -0
- agno/reasoning/default.py +97 -0
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +71 -0
- agno/reasoning/helpers.py +24 -1
- agno/reasoning/ollama.py +67 -0
- agno/reasoning/openai.py +86 -0
- agno/reasoning/step.py +2 -1
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +822 -0
- agno/run/base.py +247 -0
- agno/run/cancel.py +81 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +767 -0
- agno/run/workflow.py +708 -0
- agno/session/__init__.py +10 -0
- agno/session/agent.py +260 -0
- agno/session/summary.py +265 -0
- agno/session/team.py +342 -0
- agno/session/workflow.py +501 -0
- agno/table.py +10 -0
- agno/team/__init__.py +37 -0
- agno/team/team.py +9536 -0
- agno/tools/__init__.py +7 -0
- agno/tools/agentql.py +120 -0
- agno/tools/airflow.py +22 -12
- agno/tools/api.py +122 -0
- agno/tools/apify.py +276 -83
- agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
- agno/tools/aws_lambda.py +28 -7
- agno/tools/aws_ses.py +66 -0
- agno/tools/baidusearch.py +11 -4
- agno/tools/bitbucket.py +292 -0
- agno/tools/brandfetch.py +213 -0
- agno/tools/bravesearch.py +106 -0
- agno/tools/brightdata.py +367 -0
- agno/tools/browserbase.py +209 -0
- agno/tools/calcom.py +32 -23
- agno/tools/calculator.py +24 -37
- agno/tools/cartesia.py +187 -0
- agno/tools/{clickup_tool.py → clickup.py} +17 -28
- agno/tools/confluence.py +91 -26
- agno/tools/crawl4ai.py +139 -43
- agno/tools/csv_toolkit.py +28 -22
- agno/tools/dalle.py +36 -22
- agno/tools/daytona.py +475 -0
- agno/tools/decorator.py +169 -14
- agno/tools/desi_vocal.py +23 -11
- agno/tools/discord.py +32 -29
- agno/tools/docker.py +716 -0
- agno/tools/duckdb.py +76 -81
- agno/tools/duckduckgo.py +43 -40
- agno/tools/e2b.py +703 -0
- agno/tools/eleven_labs.py +65 -54
- agno/tools/email.py +13 -5
- agno/tools/evm.py +129 -0
- agno/tools/exa.py +324 -42
- agno/tools/fal.py +39 -35
- agno/tools/file.py +196 -30
- agno/tools/file_generation.py +356 -0
- agno/tools/financial_datasets.py +288 -0
- agno/tools/firecrawl.py +108 -33
- agno/tools/function.py +960 -122
- agno/tools/giphy.py +34 -12
- agno/tools/github.py +1294 -97
- agno/tools/gmail.py +922 -0
- agno/tools/google_bigquery.py +117 -0
- agno/tools/google_drive.py +271 -0
- agno/tools/google_maps.py +253 -0
- agno/tools/googlecalendar.py +607 -107
- agno/tools/googlesheets.py +377 -0
- agno/tools/hackernews.py +20 -12
- agno/tools/jina.py +24 -14
- agno/tools/jira.py +48 -19
- agno/tools/knowledge.py +218 -0
- agno/tools/linear.py +82 -43
- agno/tools/linkup.py +58 -0
- agno/tools/local_file_system.py +15 -7
- agno/tools/lumalab.py +41 -26
- agno/tools/mcp/__init__.py +10 -0
- agno/tools/mcp/mcp.py +331 -0
- agno/tools/mcp/multi_mcp.py +347 -0
- agno/tools/mcp/params.py +24 -0
- agno/tools/mcp_toolbox.py +284 -0
- agno/tools/mem0.py +193 -0
- agno/tools/memory.py +419 -0
- agno/tools/mlx_transcribe.py +11 -9
- agno/tools/models/azure_openai.py +190 -0
- agno/tools/models/gemini.py +203 -0
- agno/tools/models/groq.py +158 -0
- agno/tools/models/morph.py +186 -0
- agno/tools/models/nebius.py +124 -0
- agno/tools/models_labs.py +163 -82
- agno/tools/moviepy_video.py +18 -13
- agno/tools/nano_banana.py +151 -0
- agno/tools/neo4j.py +134 -0
- agno/tools/newspaper.py +15 -4
- agno/tools/newspaper4k.py +19 -6
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +181 -17
- agno/tools/openbb.py +27 -20
- agno/tools/opencv.py +321 -0
- agno/tools/openweather.py +233 -0
- agno/tools/oxylabs.py +385 -0
- agno/tools/pandas.py +25 -15
- agno/tools/parallel.py +314 -0
- agno/tools/postgres.py +238 -185
- agno/tools/pubmed.py +125 -13
- agno/tools/python.py +48 -35
- agno/tools/reasoning.py +283 -0
- agno/tools/reddit.py +207 -29
- agno/tools/redshift.py +406 -0
- agno/tools/replicate.py +69 -26
- agno/tools/resend.py +11 -6
- agno/tools/scrapegraph.py +179 -19
- agno/tools/searxng.py +23 -31
- agno/tools/serpapi.py +15 -10
- agno/tools/serper.py +255 -0
- agno/tools/shell.py +23 -12
- agno/tools/shopify.py +1519 -0
- agno/tools/slack.py +56 -14
- agno/tools/sleep.py +8 -6
- agno/tools/spider.py +35 -11
- agno/tools/spotify.py +919 -0
- agno/tools/sql.py +34 -19
- agno/tools/tavily.py +158 -8
- agno/tools/telegram.py +18 -8
- agno/tools/todoist.py +218 -0
- agno/tools/toolkit.py +134 -9
- agno/tools/trafilatura.py +388 -0
- agno/tools/trello.py +25 -28
- agno/tools/twilio.py +18 -9
- agno/tools/user_control_flow.py +78 -0
- agno/tools/valyu.py +228 -0
- agno/tools/visualization.py +467 -0
- agno/tools/webbrowser.py +28 -0
- agno/tools/webex.py +76 -0
- agno/tools/website.py +23 -19
- agno/tools/webtools.py +45 -0
- agno/tools/whatsapp.py +286 -0
- agno/tools/wikipedia.py +28 -19
- agno/tools/workflow.py +285 -0
- agno/tools/{twitter.py → x.py} +142 -46
- agno/tools/yfinance.py +41 -39
- agno/tools/youtube.py +34 -17
- agno/tools/zendesk.py +15 -5
- agno/tools/zep.py +454 -0
- agno/tools/zoom.py +86 -37
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +157 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +111 -0
- agno/utils/agent.py +938 -0
- agno/utils/audio.py +37 -1
- agno/utils/certs.py +27 -0
- agno/utils/code_execution.py +11 -0
- agno/utils/common.py +103 -20
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +700 -0
- agno/utils/functions.py +107 -37
- agno/utils/gemini.py +426 -0
- agno/utils/hooks.py +171 -0
- agno/utils/http.py +185 -0
- agno/utils/json_schema.py +159 -37
- agno/utils/knowledge.py +36 -0
- agno/utils/location.py +19 -0
- agno/utils/log.py +221 -8
- agno/utils/mcp.py +214 -0
- agno/utils/media.py +335 -14
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +77 -2
- agno/utils/models/ai_foundry.py +50 -0
- agno/utils/models/claude.py +373 -0
- agno/utils/models/cohere.py +94 -0
- agno/utils/models/llama.py +85 -0
- agno/utils/models/mistral.py +100 -0
- agno/utils/models/openai_responses.py +140 -0
- agno/utils/models/schema_utils.py +153 -0
- agno/utils/models/watsonx.py +41 -0
- agno/utils/openai.py +257 -0
- agno/utils/pickle.py +1 -1
- agno/utils/pprint.py +124 -8
- agno/utils/print_response/agent.py +930 -0
- agno/utils/print_response/team.py +1914 -0
- agno/utils/print_response/workflow.py +1668 -0
- agno/utils/prompts.py +111 -0
- agno/utils/reasoning.py +108 -0
- agno/utils/response.py +163 -0
- agno/utils/serialize.py +32 -0
- agno/utils/shell.py +4 -4
- agno/utils/streamlit.py +487 -0
- agno/utils/string.py +204 -51
- agno/utils/team.py +139 -0
- agno/utils/timer.py +9 -2
- agno/utils/tokens.py +657 -0
- agno/utils/tools.py +19 -1
- agno/utils/whatsapp.py +305 -0
- agno/utils/yaml_io.py +3 -3
- agno/vectordb/__init__.py +2 -0
- agno/vectordb/base.py +87 -9
- agno/vectordb/cassandra/__init__.py +5 -1
- agno/vectordb/cassandra/cassandra.py +383 -27
- agno/vectordb/chroma/__init__.py +4 -0
- agno/vectordb/chroma/chromadb.py +748 -83
- agno/vectordb/clickhouse/__init__.py +7 -1
- agno/vectordb/clickhouse/clickhousedb.py +554 -53
- agno/vectordb/couchbase/__init__.py +3 -0
- agno/vectordb/couchbase/couchbase.py +1446 -0
- agno/vectordb/lancedb/__init__.py +5 -0
- agno/vectordb/lancedb/lance_db.py +730 -98
- agno/vectordb/langchaindb/__init__.py +5 -0
- agno/vectordb/langchaindb/langchaindb.py +163 -0
- agno/vectordb/lightrag/__init__.py +5 -0
- agno/vectordb/lightrag/lightrag.py +388 -0
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +166 -0
- agno/vectordb/milvus/__init__.py +3 -0
- agno/vectordb/milvus/milvus.py +966 -78
- agno/vectordb/mongodb/__init__.py +9 -1
- agno/vectordb/mongodb/mongodb.py +1175 -172
- agno/vectordb/pgvector/__init__.py +8 -0
- agno/vectordb/pgvector/pgvector.py +599 -115
- agno/vectordb/pineconedb/__init__.py +5 -1
- agno/vectordb/pineconedb/pineconedb.py +406 -43
- agno/vectordb/qdrant/__init__.py +4 -0
- agno/vectordb/qdrant/qdrant.py +914 -61
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +682 -0
- agno/vectordb/singlestore/__init__.py +8 -1
- agno/vectordb/singlestore/singlestore.py +771 -0
- agno/vectordb/surrealdb/__init__.py +3 -0
- agno/vectordb/surrealdb/surrealdb.py +663 -0
- agno/vectordb/upstashdb/__init__.py +5 -0
- agno/vectordb/upstashdb/upstashdb.py +718 -0
- agno/vectordb/weaviate/__init__.py +8 -0
- agno/vectordb/weaviate/index.py +15 -0
- agno/vectordb/weaviate/weaviate.py +1009 -0
- agno/workflow/__init__.py +23 -1
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +759 -0
- agno/workflow/loop.py +756 -0
- agno/workflow/parallel.py +853 -0
- agno/workflow/router.py +723 -0
- agno/workflow/step.py +1564 -0
- agno/workflow/steps.py +613 -0
- agno/workflow/types.py +556 -0
- agno/workflow/workflow.py +4327 -514
- agno-2.3.13.dist-info/METADATA +639 -0
- agno-2.3.13.dist-info/RECORD +613 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
- agno-2.3.13.dist-info/licenses/LICENSE +201 -0
- agno/api/playground.py +0 -91
- agno/api/schemas/playground.py +0 -22
- agno/api/schemas/user.py +0 -22
- agno/api/schemas/workspace.py +0 -46
- agno/api/user.py +0 -160
- agno/api/workspace.py +0 -151
- agno/cli/auth_server.py +0 -118
- agno/cli/config.py +0 -275
- agno/cli/console.py +0 -88
- agno/cli/credentials.py +0 -23
- agno/cli/entrypoint.py +0 -571
- agno/cli/operator.py +0 -355
- agno/cli/settings.py +0 -85
- agno/cli/ws/ws_cli.py +0 -817
- agno/constants.py +0 -13
- agno/document/__init__.py +0 -1
- agno/document/chunking/semantic.py +0 -47
- agno/document/chunking/strategy.py +0 -31
- agno/document/reader/__init__.py +0 -1
- agno/document/reader/arxiv_reader.py +0 -41
- agno/document/reader/base.py +0 -22
- agno/document/reader/csv_reader.py +0 -84
- agno/document/reader/docx_reader.py +0 -46
- agno/document/reader/firecrawl_reader.py +0 -99
- agno/document/reader/json_reader.py +0 -43
- agno/document/reader/pdf_reader.py +0 -219
- agno/document/reader/s3/pdf_reader.py +0 -46
- agno/document/reader/s3/text_reader.py +0 -51
- agno/document/reader/text_reader.py +0 -41
- agno/document/reader/website_reader.py +0 -175
- agno/document/reader/youtube_reader.py +0 -50
- agno/embedder/__init__.py +0 -1
- agno/embedder/azure_openai.py +0 -86
- agno/embedder/cohere.py +0 -72
- agno/embedder/fastembed.py +0 -37
- agno/embedder/google.py +0 -73
- agno/embedder/huggingface.py +0 -54
- agno/embedder/mistral.py +0 -80
- agno/embedder/ollama.py +0 -57
- agno/embedder/openai.py +0 -74
- agno/embedder/sentence_transformer.py +0 -38
- agno/embedder/voyageai.py +0 -64
- agno/eval/perf.py +0 -201
- agno/file/__init__.py +0 -1
- 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 -230
- agno/knowledge/arxiv.py +0 -22
- agno/knowledge/combined.py +0 -22
- agno/knowledge/csv.py +0 -28
- agno/knowledge/csv_url.py +0 -19
- agno/knowledge/document.py +0 -20
- agno/knowledge/docx.py +0 -30
- agno/knowledge/json.py +0 -28
- agno/knowledge/langchain.py +0 -71
- agno/knowledge/llamaindex.py +0 -66
- agno/knowledge/pdf.py +0 -28
- agno/knowledge/pdf_url.py +0 -26
- agno/knowledge/s3/base.py +0 -60
- agno/knowledge/s3/pdf.py +0 -21
- agno/knowledge/s3/text.py +0 -23
- agno/knowledge/text.py +0 -30
- agno/knowledge/website.py +0 -88
- agno/knowledge/wikipedia.py +0 -31
- agno/knowledge/youtube.py +0 -22
- agno/memory/agent.py +0 -392
- agno/memory/classifier.py +0 -104
- agno/memory/db/__init__.py +0 -1
- 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 -15
- agno/memory/row.py +0 -36
- agno/memory/summarizer.py +0 -192
- agno/memory/summary.py +0 -19
- agno/memory/workflow.py +0 -38
- agno/models/google/gemini_openai.py +0 -26
- agno/models/ollama/hermes.py +0 -221
- agno/models/ollama/tools.py +0 -362
- agno/models/vertexai/gemini.py +0 -595
- agno/playground/__init__.py +0 -3
- agno/playground/async_router.py +0 -421
- agno/playground/deploy.py +0 -249
- agno/playground/operator.py +0 -92
- agno/playground/playground.py +0 -91
- agno/playground/schemas.py +0 -76
- agno/playground/serve.py +0 -55
- agno/playground/sync_router.py +0 -405
- agno/reasoning/agent.py +0 -68
- agno/run/response.py +0 -112
- agno/storage/agent/__init__.py +0 -0
- agno/storage/agent/base.py +0 -38
- agno/storage/agent/dynamodb.py +0 -350
- agno/storage/agent/json.py +0 -92
- agno/storage/agent/mongodb.py +0 -228
- agno/storage/agent/postgres.py +0 -367
- agno/storage/agent/session.py +0 -79
- agno/storage/agent/singlestore.py +0 -303
- agno/storage/agent/sqlite.py +0 -357
- agno/storage/agent/yaml.py +0 -93
- agno/storage/workflow/__init__.py +0 -0
- agno/storage/workflow/base.py +0 -40
- agno/storage/workflow/mongodb.py +0 -233
- agno/storage/workflow/postgres.py +0 -366
- agno/storage/workflow/session.py +0 -60
- agno/storage/workflow/sqlite.py +0 -359
- agno/tools/googlesearch.py +0 -88
- 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/vectordb/singlestore/s2vectordb.py +0 -390
- agno/vectordb/singlestore/s2vectordb2.py +0 -355
- agno/workspace/__init__.py +0 -0
- agno/workspace/config.py +0 -325
- agno/workspace/enums.py +0 -6
- agno/workspace/helpers.py +0 -48
- agno/workspace/operator.py +0 -758
- agno/workspace/settings.py +0 -63
- agno-0.1.2.dist-info/LICENSE +0 -375
- agno-0.1.2.dist-info/METADATA +0 -502
- agno-0.1.2.dist-info/RECORD +0 -352
- agno-0.1.2.dist-info/entry_points.txt +0 -3
- /agno/{cli → db/migrations}/__init__.py +0 -0
- /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
- /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
- /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
- /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
- /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
- /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
- /agno/{reranker → utils/models}/__init__.py +0 -0
- /agno/{storage → utils/print_response}/__init__.py +0 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
agno/memory/classifier.py
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
from typing import Any, List, Optional, cast
|
|
2
|
-
|
|
3
|
-
from pydantic import BaseModel
|
|
4
|
-
|
|
5
|
-
from agno.memory.memory import Memory
|
|
6
|
-
from agno.models.base import Model
|
|
7
|
-
from agno.models.message import Message
|
|
8
|
-
from agno.utils.log import logger
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class MemoryClassifier(BaseModel):
|
|
12
|
-
model: Optional[Model] = None
|
|
13
|
-
|
|
14
|
-
# Provide the system prompt for the classifier as a string
|
|
15
|
-
system_prompt: Optional[str] = None
|
|
16
|
-
# Existing Memories
|
|
17
|
-
existing_memories: Optional[List[Memory]] = None
|
|
18
|
-
|
|
19
|
-
def update_model(self) -> None:
|
|
20
|
-
if self.model is None:
|
|
21
|
-
try:
|
|
22
|
-
from agno.models.openai import OpenAIChat
|
|
23
|
-
except ModuleNotFoundError as e:
|
|
24
|
-
logger.exception(e)
|
|
25
|
-
logger.error(
|
|
26
|
-
"Agno uses `openai` as the default model provider. Please provide a `model` or install `openai`."
|
|
27
|
-
)
|
|
28
|
-
exit(1)
|
|
29
|
-
self.model = OpenAIChat(id="gpt-4o")
|
|
30
|
-
|
|
31
|
-
def get_system_message(self) -> Message:
|
|
32
|
-
# -*- Return a system message for classification
|
|
33
|
-
system_prompt_lines = [
|
|
34
|
-
"Your task is to identify if the user's message contains information that is worth remembering for future conversations.",
|
|
35
|
-
"This includes details that could personalize ongoing interactions with the user, such as:\n"
|
|
36
|
-
" - Personal facts: name, age, occupation, location, interests, preferences, etc.\n"
|
|
37
|
-
" - Significant life events or experiences shared by the user\n"
|
|
38
|
-
" - Important context about the user's current situation, challenges or goals\n"
|
|
39
|
-
" - What the user likes or dislikes, their opinions, beliefs, values, etc.\n"
|
|
40
|
-
" - Any other details that provide valuable insights into the user's personality, perspective or needs",
|
|
41
|
-
"Your task is to decide whether the user input contains any of the above information worth remembering.",
|
|
42
|
-
"If the user input contains any information worth remembering for future conversations, respond with 'yes'.",
|
|
43
|
-
"If the input does not contain any important details worth saving, respond with 'no' to disregard it.",
|
|
44
|
-
"You will also be provided with a list of existing memories to help you decide if the input is new or already known.",
|
|
45
|
-
"If the memory already exists that matches the input, respond with 'no' to keep it as is.",
|
|
46
|
-
"If a memory exists that needs to be updated or deleted, respond with 'yes' to update/delete it.",
|
|
47
|
-
"You must only respond with 'yes' or 'no'. Nothing else will be considered as a valid response.",
|
|
48
|
-
]
|
|
49
|
-
if self.existing_memories and len(self.existing_memories) > 0:
|
|
50
|
-
system_prompt_lines.extend(
|
|
51
|
-
[
|
|
52
|
-
"\nExisting memories:",
|
|
53
|
-
"<existing_memories>\n"
|
|
54
|
-
+ "\n".join([f" - {m.memory}" for m in self.existing_memories])
|
|
55
|
-
+ "\n</existing_memories>",
|
|
56
|
-
]
|
|
57
|
-
)
|
|
58
|
-
return Message(role="system", content="\n".join(system_prompt_lines))
|
|
59
|
-
|
|
60
|
-
def run(
|
|
61
|
-
self,
|
|
62
|
-
message: Optional[str] = None,
|
|
63
|
-
**kwargs: Any,
|
|
64
|
-
) -> Optional[str]:
|
|
65
|
-
logger.debug("*********** MemoryClassifier Start ***********")
|
|
66
|
-
|
|
67
|
-
# Update the Model (set defaults, add logit etc.)
|
|
68
|
-
self.update_model()
|
|
69
|
-
|
|
70
|
-
# Prepare the List of messages to send to the Model
|
|
71
|
-
messages_for_model: List[Message] = [self.get_system_message()]
|
|
72
|
-
# Add the user prompt message
|
|
73
|
-
user_prompt_message = Message(role="user", content=message, **kwargs) if message else None
|
|
74
|
-
if user_prompt_message is not None:
|
|
75
|
-
messages_for_model += [user_prompt_message]
|
|
76
|
-
|
|
77
|
-
# Generate a response from the Model (includes running function calls)
|
|
78
|
-
self.model = cast(Model, self.model)
|
|
79
|
-
response = self.model.response(messages=messages_for_model)
|
|
80
|
-
logger.debug("*********** MemoryClassifier End ***********")
|
|
81
|
-
return response.content
|
|
82
|
-
|
|
83
|
-
async def arun(
|
|
84
|
-
self,
|
|
85
|
-
message: Optional[str] = None,
|
|
86
|
-
**kwargs: Any,
|
|
87
|
-
) -> Optional[str]:
|
|
88
|
-
logger.debug("*********** Async MemoryClassifier Start ***********")
|
|
89
|
-
|
|
90
|
-
# Update the Model (set defaults, add logit etc.)
|
|
91
|
-
self.update_model()
|
|
92
|
-
|
|
93
|
-
# Prepare the List of messages to send to the Model
|
|
94
|
-
messages_for_model: List[Message] = [self.get_system_message()]
|
|
95
|
-
# Add the user prompt message
|
|
96
|
-
user_prompt_message = Message(role="user", content=message, **kwargs) if message else None
|
|
97
|
-
if user_prompt_message is not None:
|
|
98
|
-
messages_for_model += [user_prompt_message]
|
|
99
|
-
|
|
100
|
-
# Generate a response from the Model (includes running function calls)
|
|
101
|
-
self.model = cast(Model, self.model)
|
|
102
|
-
response = await self.model.aresponse(messages=messages_for_model)
|
|
103
|
-
logger.debug("*********** Async MemoryClassifier End ***********")
|
|
104
|
-
return response.content
|
agno/memory/db/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from agno.memory.db.base import MemoryDb
|
agno/memory/db/base.py
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
from abc import ABC, abstractmethod
|
|
2
|
-
from typing import List, Optional
|
|
3
|
-
|
|
4
|
-
from agno.memory.row import MemoryRow
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class MemoryDb(ABC):
|
|
8
|
-
"""Base class for the Memory Database."""
|
|
9
|
-
|
|
10
|
-
@abstractmethod
|
|
11
|
-
def create(self) -> None:
|
|
12
|
-
raise NotImplementedError
|
|
13
|
-
|
|
14
|
-
@abstractmethod
|
|
15
|
-
def memory_exists(self, memory: MemoryRow) -> bool:
|
|
16
|
-
raise NotImplementedError
|
|
17
|
-
|
|
18
|
-
@abstractmethod
|
|
19
|
-
def read_memories(
|
|
20
|
-
self, user_id: Optional[str] = None, limit: Optional[int] = None, sort: Optional[str] = None
|
|
21
|
-
) -> List[MemoryRow]:
|
|
22
|
-
raise NotImplementedError
|
|
23
|
-
|
|
24
|
-
@abstractmethod
|
|
25
|
-
def upsert_memory(self, memory: MemoryRow) -> Optional[MemoryRow]:
|
|
26
|
-
raise NotImplementedError
|
|
27
|
-
|
|
28
|
-
@abstractmethod
|
|
29
|
-
def delete_memory(self, id: str) -> None:
|
|
30
|
-
raise NotImplementedError
|
|
31
|
-
|
|
32
|
-
@abstractmethod
|
|
33
|
-
def drop_table(self) -> None:
|
|
34
|
-
raise NotImplementedError
|
|
35
|
-
|
|
36
|
-
@abstractmethod
|
|
37
|
-
def table_exists(self) -> bool:
|
|
38
|
-
raise NotImplementedError
|
|
39
|
-
|
|
40
|
-
@abstractmethod
|
|
41
|
-
def clear(self) -> bool:
|
|
42
|
-
raise NotImplementedError
|
agno/memory/db/mongodb.py
DELETED
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
from datetime import datetime, timezone
|
|
2
|
-
from typing import 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.db import MemoryDb
|
|
13
|
-
from agno.memory.row import MemoryRow
|
|
14
|
-
from agno.utils.log import 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 create(self) -> None:
|
|
47
|
-
"""Create indexes for the collection"""
|
|
48
|
-
try:
|
|
49
|
-
# Create indexes
|
|
50
|
-
self.collection.create_index("id", unique=True)
|
|
51
|
-
self.collection.create_index("user_id")
|
|
52
|
-
self.collection.create_index("created_at")
|
|
53
|
-
except PyMongoError as e:
|
|
54
|
-
logger.error(f"Error creating indexes for collection '{self.collection_name}': {e}")
|
|
55
|
-
raise
|
|
56
|
-
|
|
57
|
-
def memory_exists(self, memory: MemoryRow) -> bool:
|
|
58
|
-
"""Check if a memory exists
|
|
59
|
-
Args:
|
|
60
|
-
memory: MemoryRow to check
|
|
61
|
-
Returns:
|
|
62
|
-
bool: True if the memory exists, False otherwise
|
|
63
|
-
"""
|
|
64
|
-
try:
|
|
65
|
-
result = self.collection.find_one({"id": memory.id})
|
|
66
|
-
return result is not None
|
|
67
|
-
except PyMongoError as e:
|
|
68
|
-
logger.error(f"Error checking memory existence: {e}")
|
|
69
|
-
return False
|
|
70
|
-
|
|
71
|
-
def read_memories(
|
|
72
|
-
self, user_id: Optional[str] = None, limit: Optional[int] = None, sort: Optional[str] = None
|
|
73
|
-
) -> List[MemoryRow]:
|
|
74
|
-
"""Read memories from the collection
|
|
75
|
-
Args:
|
|
76
|
-
user_id: ID of the user to read
|
|
77
|
-
limit: Maximum number of memories to read
|
|
78
|
-
sort: Sort order ("asc" or "desc")
|
|
79
|
-
Returns:
|
|
80
|
-
List[MemoryRow]: List of memories
|
|
81
|
-
"""
|
|
82
|
-
memories: List[MemoryRow] = []
|
|
83
|
-
try:
|
|
84
|
-
# Build query
|
|
85
|
-
query = {}
|
|
86
|
-
if user_id is not None:
|
|
87
|
-
query["user_id"] = user_id
|
|
88
|
-
|
|
89
|
-
# Build sort order
|
|
90
|
-
sort_order = -1 if sort != "asc" else 1
|
|
91
|
-
cursor = self.collection.find(query).sort("created_at", sort_order)
|
|
92
|
-
|
|
93
|
-
if limit is not None:
|
|
94
|
-
cursor = cursor.limit(limit)
|
|
95
|
-
|
|
96
|
-
for doc in cursor:
|
|
97
|
-
# Remove MongoDB _id before converting to MemoryRow
|
|
98
|
-
doc.pop("_id", None)
|
|
99
|
-
memories.append(MemoryRow(id=doc["id"], user_id=doc["user_id"], memory=doc["memory"]))
|
|
100
|
-
except PyMongoError as e:
|
|
101
|
-
logger.error(f"Error reading memories: {e}")
|
|
102
|
-
return memories
|
|
103
|
-
|
|
104
|
-
def upsert_memory(self, memory: MemoryRow, create_and_retry: bool = True) -> None:
|
|
105
|
-
"""Upsert a memory into the collection
|
|
106
|
-
Args:
|
|
107
|
-
memory: MemoryRow to upsert
|
|
108
|
-
create_and_retry: Whether to create a new memory if the id already exists
|
|
109
|
-
Returns:
|
|
110
|
-
None
|
|
111
|
-
"""
|
|
112
|
-
try:
|
|
113
|
-
now = datetime.now(timezone.utc)
|
|
114
|
-
timestamp = int(now.timestamp())
|
|
115
|
-
|
|
116
|
-
# Add version field for optimistic locking
|
|
117
|
-
memory_dict = memory.model_dump()
|
|
118
|
-
if "_version" not in memory_dict:
|
|
119
|
-
memory_dict["_version"] = 1
|
|
120
|
-
else:
|
|
121
|
-
memory_dict["_version"] += 1
|
|
122
|
-
|
|
123
|
-
update_data = {
|
|
124
|
-
"user_id": memory.user_id,
|
|
125
|
-
"memory": memory.memory,
|
|
126
|
-
"updated_at": timestamp,
|
|
127
|
-
"_version": memory_dict["_version"],
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
# For new documents, set created_at
|
|
131
|
-
query = {"id": memory.id}
|
|
132
|
-
doc = self.collection.find_one(query)
|
|
133
|
-
if not doc:
|
|
134
|
-
update_data["created_at"] = timestamp
|
|
135
|
-
|
|
136
|
-
result = self.collection.update_one(query, {"$set": update_data}, upsert=True)
|
|
137
|
-
|
|
138
|
-
if not result.acknowledged:
|
|
139
|
-
logger.error("Memory upsert not acknowledged")
|
|
140
|
-
|
|
141
|
-
except PyMongoError as e:
|
|
142
|
-
logger.error(f"Error upserting memory: {e}")
|
|
143
|
-
raise
|
|
144
|
-
|
|
145
|
-
def delete_memory(self, id: str) -> None:
|
|
146
|
-
"""Delete a memory from the collection
|
|
147
|
-
Args:
|
|
148
|
-
id: ID of the memory to delete
|
|
149
|
-
Returns:
|
|
150
|
-
None
|
|
151
|
-
"""
|
|
152
|
-
try:
|
|
153
|
-
result = self.collection.delete_one({"id": id})
|
|
154
|
-
if result.deleted_count == 0:
|
|
155
|
-
logger.debug(f"No memory found with id: {id}")
|
|
156
|
-
else:
|
|
157
|
-
logger.debug(f"Successfully deleted memory with id: {id}")
|
|
158
|
-
except PyMongoError as e:
|
|
159
|
-
logger.error(f"Error deleting memory: {e}")
|
|
160
|
-
raise
|
|
161
|
-
|
|
162
|
-
def drop_table(self) -> None:
|
|
163
|
-
"""Drop the collection
|
|
164
|
-
Returns:
|
|
165
|
-
None
|
|
166
|
-
"""
|
|
167
|
-
try:
|
|
168
|
-
self.collection.drop()
|
|
169
|
-
except PyMongoError as e:
|
|
170
|
-
logger.error(f"Error dropping collection: {e}")
|
|
171
|
-
|
|
172
|
-
def table_exists(self) -> bool:
|
|
173
|
-
"""Check if the collection exists
|
|
174
|
-
Returns:
|
|
175
|
-
bool: True if the collection exists, False otherwise
|
|
176
|
-
"""
|
|
177
|
-
return self.collection_name in self.db.list_collection_names()
|
|
178
|
-
|
|
179
|
-
def clear(self) -> bool:
|
|
180
|
-
"""Clear the collection
|
|
181
|
-
Returns:
|
|
182
|
-
bool: True if the collection was cleared, False otherwise
|
|
183
|
-
"""
|
|
184
|
-
try:
|
|
185
|
-
result = self.collection.delete_many({})
|
|
186
|
-
return result.acknowledged
|
|
187
|
-
except PyMongoError as e:
|
|
188
|
-
logger.error(f"Error clearing collection: {e}")
|
|
189
|
-
return False
|
agno/memory/db/postgres.py
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
from typing import 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")
|
|
13
|
-
|
|
14
|
-
from agno.memory.db import MemoryDb
|
|
15
|
-
from agno.memory.row import MemoryRow
|
|
16
|
-
from agno.utils.log import logger
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class PgMemoryDb(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 get_table(self) -> Table:
|
|
57
|
-
return Table(
|
|
58
|
-
self.table_name,
|
|
59
|
-
self.metadata,
|
|
60
|
-
Column("id", String, primary_key=True),
|
|
61
|
-
Column("user_id", String),
|
|
62
|
-
Column("memory", postgresql.JSONB, server_default=text("'{}'::jsonb")),
|
|
63
|
-
Column("created_at", DateTime(timezone=True), server_default=text("now()")),
|
|
64
|
-
Column("updated_at", DateTime(timezone=True), onupdate=text("now()")),
|
|
65
|
-
extend_existing=True,
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
def create(self) -> None:
|
|
69
|
-
if not self.table_exists():
|
|
70
|
-
try:
|
|
71
|
-
with self.Session() as sess, sess.begin():
|
|
72
|
-
if self.schema is not None:
|
|
73
|
-
logger.debug(f"Creating schema: {self.schema}")
|
|
74
|
-
sess.execute(text(f"CREATE SCHEMA IF NOT EXISTS {self.schema};"))
|
|
75
|
-
logger.debug(f"Creating table: {self.table_name}")
|
|
76
|
-
self.table.create(self.db_engine, checkfirst=True)
|
|
77
|
-
except Exception as e:
|
|
78
|
-
logger.error(f"Error creating table '{self.table.fullname}': {e}")
|
|
79
|
-
raise
|
|
80
|
-
|
|
81
|
-
def memory_exists(self, memory: MemoryRow) -> bool:
|
|
82
|
-
columns = [self.table.c.id]
|
|
83
|
-
with self.Session() as sess, sess.begin():
|
|
84
|
-
stmt = select(*columns).where(self.table.c.id == memory.id)
|
|
85
|
-
result = sess.execute(stmt).first()
|
|
86
|
-
return result is not None
|
|
87
|
-
|
|
88
|
-
def read_memories(
|
|
89
|
-
self, user_id: Optional[str] = None, limit: Optional[int] = None, sort: Optional[str] = None
|
|
90
|
-
) -> List[MemoryRow]:
|
|
91
|
-
memories: List[MemoryRow] = []
|
|
92
|
-
try:
|
|
93
|
-
with self.Session() as sess, sess.begin():
|
|
94
|
-
stmt = select(self.table)
|
|
95
|
-
if user_id is not None:
|
|
96
|
-
stmt = stmt.where(self.table.c.user_id == user_id)
|
|
97
|
-
if limit is not None:
|
|
98
|
-
stmt = stmt.limit(limit)
|
|
99
|
-
|
|
100
|
-
if sort == "asc":
|
|
101
|
-
stmt = stmt.order_by(self.table.c.created_at.asc())
|
|
102
|
-
else:
|
|
103
|
-
stmt = stmt.order_by(self.table.c.created_at.desc())
|
|
104
|
-
|
|
105
|
-
rows = sess.execute(stmt).fetchall()
|
|
106
|
-
for row in rows:
|
|
107
|
-
if row is not None:
|
|
108
|
-
memories.append(MemoryRow.model_validate(row))
|
|
109
|
-
except Exception as e:
|
|
110
|
-
logger.debug(f"Exception reading from table: {e}")
|
|
111
|
-
logger.debug(f"Table does not exist: {self.table.name}")
|
|
112
|
-
logger.debug("Creating table for future transactions")
|
|
113
|
-
self.create()
|
|
114
|
-
return memories
|
|
115
|
-
|
|
116
|
-
def upsert_memory(self, memory: MemoryRow, create_and_retry: bool = True) -> None:
|
|
117
|
-
"""Create a new memory if it does not exist, otherwise update the existing memory"""
|
|
118
|
-
|
|
119
|
-
try:
|
|
120
|
-
with self.Session() as sess, sess.begin():
|
|
121
|
-
# Create an insert statement
|
|
122
|
-
stmt = postgresql.insert(self.table).values(
|
|
123
|
-
id=memory.id,
|
|
124
|
-
user_id=memory.user_id,
|
|
125
|
-
memory=memory.memory,
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
# Define the upsert if the memory already exists
|
|
129
|
-
# See: https://docs.sqlalchemy.org/en/20/dialects/postgresql.html#postgresql-insert-on-conflict
|
|
130
|
-
stmt = stmt.on_conflict_do_update(
|
|
131
|
-
index_elements=["id"],
|
|
132
|
-
set_=dict(
|
|
133
|
-
user_id=stmt.excluded.user_id,
|
|
134
|
-
memory=stmt.excluded.memory,
|
|
135
|
-
),
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
sess.execute(stmt)
|
|
139
|
-
except Exception as e:
|
|
140
|
-
logger.debug(f"Exception upserting into table: {e}")
|
|
141
|
-
logger.debug(f"Table does not exist: {self.table.name}")
|
|
142
|
-
logger.debug("Creating table for future transactions")
|
|
143
|
-
self.create()
|
|
144
|
-
if create_and_retry:
|
|
145
|
-
return self.upsert_memory(memory, create_and_retry=False)
|
|
146
|
-
return None
|
|
147
|
-
|
|
148
|
-
def delete_memory(self, id: str) -> None:
|
|
149
|
-
with self.Session() as sess, sess.begin():
|
|
150
|
-
stmt = delete(self.table).where(self.table.c.id == id)
|
|
151
|
-
sess.execute(stmt)
|
|
152
|
-
|
|
153
|
-
def drop_table(self) -> None:
|
|
154
|
-
if self.table_exists():
|
|
155
|
-
logger.debug(f"Deleting table: {self.table_name}")
|
|
156
|
-
self.table.drop(self.db_engine)
|
|
157
|
-
|
|
158
|
-
def table_exists(self) -> bool:
|
|
159
|
-
logger.debug(f"Checking if table exists: {self.table.name}")
|
|
160
|
-
try:
|
|
161
|
-
return inspect(self.db_engine).has_table(self.table.name, schema=self.schema)
|
|
162
|
-
except Exception as e:
|
|
163
|
-
logger.error(e)
|
|
164
|
-
return False
|
|
165
|
-
|
|
166
|
-
def clear(self) -> bool:
|
|
167
|
-
with self.Session() as sess, sess.begin():
|
|
168
|
-
stmt = delete(self.table)
|
|
169
|
-
sess.execute(stmt)
|
|
170
|
-
return True
|
|
171
|
-
|
|
172
|
-
def __deepcopy__(self, memo):
|
|
173
|
-
"""
|
|
174
|
-
Create a deep copy of the PgMemoryDb instance, handling unpickleable attributes.
|
|
175
|
-
|
|
176
|
-
Args:
|
|
177
|
-
memo (dict): A dictionary of objects already copied during the current copying pass.
|
|
178
|
-
|
|
179
|
-
Returns:
|
|
180
|
-
PgMemoryDb: A deep-copied instance of PgMemoryDb.
|
|
181
|
-
"""
|
|
182
|
-
from copy import deepcopy
|
|
183
|
-
|
|
184
|
-
# Create a new instance without calling __init__
|
|
185
|
-
cls = self.__class__
|
|
186
|
-
copied_obj = cls.__new__(cls)
|
|
187
|
-
memo[id(self)] = copied_obj
|
|
188
|
-
|
|
189
|
-
# Deep copy attributes
|
|
190
|
-
for k, v in self.__dict__.items():
|
|
191
|
-
if k in {"metadata", "table"}:
|
|
192
|
-
continue
|
|
193
|
-
# Reuse db_engine and Session without copying
|
|
194
|
-
elif k in {"db_engine", "Session"}:
|
|
195
|
-
setattr(copied_obj, k, v)
|
|
196
|
-
else:
|
|
197
|
-
setattr(copied_obj, k, deepcopy(v, memo))
|
|
198
|
-
|
|
199
|
-
# Recreate metadata and table for the copied instance
|
|
200
|
-
copied_obj.metadata = MetaData(schema=copied_obj.schema)
|
|
201
|
-
copied_obj.table = copied_obj.get_table()
|
|
202
|
-
|
|
203
|
-
return copied_obj
|