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
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from typing import Any, List, Optional
|
|
3
|
-
|
|
4
|
-
try:
|
|
5
|
-
from sqlalchemy.dialects import mysql
|
|
6
|
-
from sqlalchemy.engine import Engine, create_engine
|
|
7
|
-
from sqlalchemy.engine.row import Row
|
|
8
|
-
from sqlalchemy.inspection import inspect
|
|
9
|
-
from sqlalchemy.orm import Session, sessionmaker
|
|
10
|
-
from sqlalchemy.schema import Column, MetaData, Table
|
|
11
|
-
from sqlalchemy.sql.expression import select, text
|
|
12
|
-
except ImportError:
|
|
13
|
-
raise ImportError("`sqlalchemy` not installed")
|
|
14
|
-
|
|
15
|
-
from agno.storage.agent.base import AgentStorage
|
|
16
|
-
from agno.storage.agent.session import AgentSession
|
|
17
|
-
from agno.utils.log import logger
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class SingleStoreAgentStorage(AgentStorage):
|
|
21
|
-
def __init__(
|
|
22
|
-
self,
|
|
23
|
-
table_name: str,
|
|
24
|
-
schema: Optional[str] = "ai",
|
|
25
|
-
db_url: Optional[str] = None,
|
|
26
|
-
db_engine: Optional[Engine] = None,
|
|
27
|
-
schema_version: int = 1,
|
|
28
|
-
auto_upgrade_schema: bool = False,
|
|
29
|
-
):
|
|
30
|
-
"""
|
|
31
|
-
This class provides Agent storage using a singlestore table.
|
|
32
|
-
|
|
33
|
-
The following order is used to determine the database connection:
|
|
34
|
-
1. Use the db_engine if provided
|
|
35
|
-
2. Use the db_url if provided
|
|
36
|
-
|
|
37
|
-
Args:
|
|
38
|
-
table_name (str): The name of the table to store the agent data.
|
|
39
|
-
schema (Optional[str], optional): The schema of the table. Defaults to "ai".
|
|
40
|
-
db_url (Optional[str], optional): The database URL. Defaults to None.
|
|
41
|
-
db_engine (Optional[Engine], optional): The database engine. Defaults to None.
|
|
42
|
-
schema_version (int, optional): The schema version. Defaults to 1.
|
|
43
|
-
auto_upgrade_schema (bool, optional): Automatically upgrade the schema. Defaults to False.
|
|
44
|
-
"""
|
|
45
|
-
_engine: Optional[Engine] = db_engine
|
|
46
|
-
if _engine is None and db_url is not None:
|
|
47
|
-
_engine = create_engine(db_url, connect_args={"charset": "utf8mb4"})
|
|
48
|
-
|
|
49
|
-
if _engine is None:
|
|
50
|
-
raise ValueError("Must provide either db_url or db_engine")
|
|
51
|
-
|
|
52
|
-
# Database attributes
|
|
53
|
-
self.table_name: str = table_name
|
|
54
|
-
self.schema: Optional[str] = schema
|
|
55
|
-
self.db_url: Optional[str] = db_url
|
|
56
|
-
self.db_engine: Engine = _engine
|
|
57
|
-
self.metadata: MetaData = MetaData(schema=self.schema)
|
|
58
|
-
|
|
59
|
-
# Table schema version
|
|
60
|
-
self.schema_version: int = schema_version
|
|
61
|
-
# Automatically upgrade schema if True
|
|
62
|
-
self.auto_upgrade_schema: bool = auto_upgrade_schema
|
|
63
|
-
|
|
64
|
-
# Database session
|
|
65
|
-
self.Session: sessionmaker[Session] = sessionmaker(bind=self.db_engine)
|
|
66
|
-
# Database table for storage
|
|
67
|
-
self.table: Table = self.get_table()
|
|
68
|
-
|
|
69
|
-
def get_table_v1(self) -> Table:
|
|
70
|
-
return Table(
|
|
71
|
-
self.table_name,
|
|
72
|
-
self.metadata,
|
|
73
|
-
# Session UUID: Primary Key
|
|
74
|
-
Column("session_id", mysql.TEXT, primary_key=True),
|
|
75
|
-
# ID of the agent that this session is associated with
|
|
76
|
-
Column("agent_id", mysql.TEXT),
|
|
77
|
-
# ID of the user interacting with this agent
|
|
78
|
-
Column("user_id", mysql.TEXT),
|
|
79
|
-
# Agent memory
|
|
80
|
-
Column("memory", mysql.JSON),
|
|
81
|
-
# Agent Data
|
|
82
|
-
Column("agent_data", mysql.JSON),
|
|
83
|
-
# Session Data
|
|
84
|
-
Column("session_data", mysql.JSON),
|
|
85
|
-
# Extra Data stored with this agent
|
|
86
|
-
Column("extra_data", mysql.JSON),
|
|
87
|
-
# The Unix timestamp of when this session was created.
|
|
88
|
-
Column("created_at", mysql.BIGINT),
|
|
89
|
-
# The Unix timestamp of when this session was last updated.
|
|
90
|
-
Column("updated_at", mysql.BIGINT),
|
|
91
|
-
extend_existing=True,
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
def get_table(self) -> Table:
|
|
95
|
-
if self.schema_version == 1:
|
|
96
|
-
return self.get_table_v1()
|
|
97
|
-
else:
|
|
98
|
-
raise ValueError(f"Unsupported schema version: {self.schema_version}")
|
|
99
|
-
|
|
100
|
-
def table_exists(self) -> bool:
|
|
101
|
-
logger.debug(f"Checking if table exists: {self.table.name}")
|
|
102
|
-
try:
|
|
103
|
-
return inspect(self.db_engine).has_table(self.table.name, schema=self.schema)
|
|
104
|
-
except Exception as e:
|
|
105
|
-
logger.error(e)
|
|
106
|
-
return False
|
|
107
|
-
|
|
108
|
-
def create(self) -> None:
|
|
109
|
-
if not self.table_exists():
|
|
110
|
-
logger.info(f"\nCreating table: {self.table_name}\n")
|
|
111
|
-
self.table.create(self.db_engine)
|
|
112
|
-
|
|
113
|
-
def _read(self, session: Session, session_id: str, user_id: Optional[str] = None) -> Optional[Row[Any]]:
|
|
114
|
-
stmt = select(self.table).where(self.table.c.session_id == session_id)
|
|
115
|
-
if user_id is not None:
|
|
116
|
-
stmt = stmt.where(self.table.c.user_id == user_id)
|
|
117
|
-
try:
|
|
118
|
-
return session.execute(stmt).first()
|
|
119
|
-
except Exception as e:
|
|
120
|
-
logger.debug(f"Exception reading from table: {e}")
|
|
121
|
-
logger.debug(f"Table does not exist: {self.table.name}")
|
|
122
|
-
logger.debug(f"Creating table: {self.table_name}")
|
|
123
|
-
self.create()
|
|
124
|
-
return None
|
|
125
|
-
|
|
126
|
-
def read(self, session_id: str, user_id: Optional[str] = None) -> Optional[AgentSession]:
|
|
127
|
-
with self.Session.begin() as sess:
|
|
128
|
-
existing_row: Optional[Row[Any]] = self._read(session=sess, session_id=session_id, user_id=user_id)
|
|
129
|
-
return AgentSession.from_dict(existing_row._mapping) if existing_row is not None else None # type: ignore
|
|
130
|
-
|
|
131
|
-
def get_all_session_ids(self, user_id: Optional[str] = None, agent_id: Optional[str] = None) -> List[str]:
|
|
132
|
-
session_ids: List[str] = []
|
|
133
|
-
try:
|
|
134
|
-
with self.Session.begin() as sess:
|
|
135
|
-
# get all session_ids for this user
|
|
136
|
-
stmt = select(self.table)
|
|
137
|
-
if user_id is not None:
|
|
138
|
-
stmt = stmt.where(self.table.c.user_id == user_id)
|
|
139
|
-
if agent_id is not None:
|
|
140
|
-
stmt = stmt.where(self.table.c.agent_id == agent_id)
|
|
141
|
-
# order by created_at desc
|
|
142
|
-
stmt = stmt.order_by(self.table.c.created_at.desc())
|
|
143
|
-
# execute query
|
|
144
|
-
rows = sess.execute(stmt).fetchall()
|
|
145
|
-
for row in rows:
|
|
146
|
-
if row is not None and row.session_id is not None:
|
|
147
|
-
session_ids.append(row.session_id)
|
|
148
|
-
except Exception as e:
|
|
149
|
-
logger.error(f"An unexpected error occurred: {str(e)}")
|
|
150
|
-
return session_ids
|
|
151
|
-
|
|
152
|
-
def get_all_sessions(self, user_id: Optional[str] = None, agent_id: Optional[str] = None) -> List[AgentSession]:
|
|
153
|
-
sessions: List[AgentSession] = []
|
|
154
|
-
try:
|
|
155
|
-
with self.Session.begin() as sess:
|
|
156
|
-
# get all sessions for this user
|
|
157
|
-
stmt = select(self.table)
|
|
158
|
-
if user_id is not None:
|
|
159
|
-
stmt = stmt.where(self.table.c.user_id == user_id)
|
|
160
|
-
if agent_id is not None:
|
|
161
|
-
stmt = stmt.where(self.table.c.agent_id == agent_id)
|
|
162
|
-
# order by created_at desc
|
|
163
|
-
stmt = stmt.order_by(self.table.c.created_at.desc())
|
|
164
|
-
# execute query
|
|
165
|
-
rows = sess.execute(stmt).fetchall()
|
|
166
|
-
for row in rows:
|
|
167
|
-
if row.session_id is not None:
|
|
168
|
-
_agent_session = AgentSession.from_dict(row._mapping) # type: ignore
|
|
169
|
-
if _agent_session is not None:
|
|
170
|
-
sessions.append(_agent_session)
|
|
171
|
-
except Exception:
|
|
172
|
-
logger.debug(f"Table does not exist: {self.table.name}")
|
|
173
|
-
return sessions
|
|
174
|
-
|
|
175
|
-
def upsert(self, session: AgentSession) -> Optional[AgentSession]:
|
|
176
|
-
"""
|
|
177
|
-
Create a new session if it does not exist, otherwise update the existing session.
|
|
178
|
-
"""
|
|
179
|
-
|
|
180
|
-
with self.Session.begin() as sess:
|
|
181
|
-
# Create an insert statement using MySQL's ON DUPLICATE KEY UPDATE syntax
|
|
182
|
-
upsert_sql = text(
|
|
183
|
-
f"""
|
|
184
|
-
INSERT INTO {self.schema}.{self.table_name}
|
|
185
|
-
(session_id, agent_id, user_id, memory, agent_data, session_data, extra_data, created_at, updated_at)
|
|
186
|
-
VALUES
|
|
187
|
-
(:session_id, :agent_id, :user_id, :memory, :agent_data, :session_data, :extra_data, UNIX_TIMESTAMP(), NULL)
|
|
188
|
-
ON DUPLICATE KEY UPDATE
|
|
189
|
-
agent_id = VALUES(agent_id),
|
|
190
|
-
user_id = VALUES(user_id),
|
|
191
|
-
memory = VALUES(memory),
|
|
192
|
-
agent_data = VALUES(agent_data),
|
|
193
|
-
session_data = VALUES(session_data),
|
|
194
|
-
extra_data = VALUES(extra_data),
|
|
195
|
-
updated_at = UNIX_TIMESTAMP();
|
|
196
|
-
"""
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
try:
|
|
200
|
-
sess.execute(
|
|
201
|
-
upsert_sql,
|
|
202
|
-
{
|
|
203
|
-
"session_id": session.session_id,
|
|
204
|
-
"agent_id": session.agent_id,
|
|
205
|
-
"user_id": session.user_id,
|
|
206
|
-
"memory": json.dumps(session.memory, ensure_ascii=False)
|
|
207
|
-
if session.memory is not None
|
|
208
|
-
else None,
|
|
209
|
-
"agent_data": json.dumps(session.agent_data, ensure_ascii=False)
|
|
210
|
-
if session.agent_data is not None
|
|
211
|
-
else None,
|
|
212
|
-
"session_data": json.dumps(session.session_data, ensure_ascii=False)
|
|
213
|
-
if session.session_data is not None
|
|
214
|
-
else None,
|
|
215
|
-
"extra_data": json.dumps(session.extra_data, ensure_ascii=False)
|
|
216
|
-
if session.extra_data is not None
|
|
217
|
-
else None,
|
|
218
|
-
},
|
|
219
|
-
)
|
|
220
|
-
except Exception:
|
|
221
|
-
# Create table and try again
|
|
222
|
-
self.create()
|
|
223
|
-
sess.execute(
|
|
224
|
-
upsert_sql,
|
|
225
|
-
{
|
|
226
|
-
"session_id": session.session_id,
|
|
227
|
-
"agent_id": session.agent_id,
|
|
228
|
-
"user_id": session.user_id,
|
|
229
|
-
"memory": json.dumps(session.memory, ensure_ascii=False)
|
|
230
|
-
if session.memory is not None
|
|
231
|
-
else None,
|
|
232
|
-
"agent_data": json.dumps(session.agent_data, ensure_ascii=False)
|
|
233
|
-
if session.agent_data is not None
|
|
234
|
-
else None,
|
|
235
|
-
"session_data": json.dumps(session.session_data, ensure_ascii=False)
|
|
236
|
-
if session.session_data is not None
|
|
237
|
-
else None,
|
|
238
|
-
"extra_data": json.dumps(session.extra_data, ensure_ascii=False)
|
|
239
|
-
if session.extra_data is not None
|
|
240
|
-
else None,
|
|
241
|
-
},
|
|
242
|
-
)
|
|
243
|
-
return self.read(session_id=session.session_id)
|
|
244
|
-
|
|
245
|
-
def delete_session(self, session_id: Optional[str] = None):
|
|
246
|
-
if session_id is None:
|
|
247
|
-
logger.warning("No session_id provided for deletion.")
|
|
248
|
-
return
|
|
249
|
-
|
|
250
|
-
with self.Session() as sess, sess.begin():
|
|
251
|
-
try:
|
|
252
|
-
# Delete the session with the given session_id
|
|
253
|
-
delete_stmt = self.table.delete().where(self.table.c.session_id == session_id)
|
|
254
|
-
result = sess.execute(delete_stmt)
|
|
255
|
-
|
|
256
|
-
if result.rowcount == 0:
|
|
257
|
-
logger.warning(f"No session found with session_id: {session_id}")
|
|
258
|
-
else:
|
|
259
|
-
logger.info(f"Successfully deleted session with session_id: {session_id}")
|
|
260
|
-
except Exception as e:
|
|
261
|
-
logger.error(f"Error deleting session: {e}")
|
|
262
|
-
raise
|
|
263
|
-
|
|
264
|
-
def drop(self) -> None:
|
|
265
|
-
if self.table_exists():
|
|
266
|
-
logger.info(f"Deleting table: {self.table_name}")
|
|
267
|
-
self.table.drop(self.db_engine)
|
|
268
|
-
|
|
269
|
-
def upgrade_schema(self) -> None:
|
|
270
|
-
pass
|
|
271
|
-
|
|
272
|
-
def __deepcopy__(self, memo):
|
|
273
|
-
"""
|
|
274
|
-
Create a deep copy of the SingleStoreAgentStorage instance, handling unpickleable attributes.
|
|
275
|
-
|
|
276
|
-
Args:
|
|
277
|
-
memo (dict): A dictionary of objects already copied during the current copying pass.
|
|
278
|
-
|
|
279
|
-
Returns:
|
|
280
|
-
SingleStoreAgentStorage: A deep-copied instance of SingleStoreAgentStorage.
|
|
281
|
-
"""
|
|
282
|
-
from copy import deepcopy
|
|
283
|
-
|
|
284
|
-
# Create a new instance without calling __init__
|
|
285
|
-
cls = self.__class__
|
|
286
|
-
copied_obj = cls.__new__(cls)
|
|
287
|
-
memo[id(self)] = copied_obj
|
|
288
|
-
|
|
289
|
-
# Deep copy attributes
|
|
290
|
-
for k, v in self.__dict__.items():
|
|
291
|
-
if k in {"metadata", "table"}:
|
|
292
|
-
continue
|
|
293
|
-
# Reuse db_engine and Session without copying
|
|
294
|
-
elif k in {"db_engine", "Session"}:
|
|
295
|
-
setattr(copied_obj, k, v)
|
|
296
|
-
else:
|
|
297
|
-
setattr(copied_obj, k, deepcopy(v, memo))
|
|
298
|
-
|
|
299
|
-
# Recreate metadata and table for the copied instance
|
|
300
|
-
copied_obj.metadata = MetaData(schema=self.schema)
|
|
301
|
-
copied_obj.table = copied_obj.get_table()
|
|
302
|
-
|
|
303
|
-
return copied_obj
|
agno/storage/agent/sqlite.py
DELETED
|
@@ -1,357 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from typing import List, Optional
|
|
4
|
-
|
|
5
|
-
try:
|
|
6
|
-
from sqlalchemy.dialects import sqlite
|
|
7
|
-
from sqlalchemy.engine import Engine, create_engine
|
|
8
|
-
from sqlalchemy.inspection import inspect
|
|
9
|
-
from sqlalchemy.orm import Session, sessionmaker
|
|
10
|
-
from sqlalchemy.schema import Column, MetaData, Table
|
|
11
|
-
from sqlalchemy.sql.expression import select
|
|
12
|
-
from sqlalchemy.types import String
|
|
13
|
-
except ImportError:
|
|
14
|
-
raise ImportError("`sqlalchemy` not installed. Please install it using `pip install sqlalchemy`")
|
|
15
|
-
|
|
16
|
-
from agno.storage.agent.base import AgentStorage
|
|
17
|
-
from agno.storage.agent.session import AgentSession
|
|
18
|
-
from agno.utils.log import logger
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class SqliteAgentStorage(AgentStorage):
|
|
22
|
-
def __init__(
|
|
23
|
-
self,
|
|
24
|
-
table_name: str,
|
|
25
|
-
db_url: Optional[str] = None,
|
|
26
|
-
db_file: Optional[str] = None,
|
|
27
|
-
db_engine: Optional[Engine] = None,
|
|
28
|
-
schema_version: int = 1,
|
|
29
|
-
auto_upgrade_schema: bool = False,
|
|
30
|
-
):
|
|
31
|
-
"""
|
|
32
|
-
This class provides agent storage using a sqlite database.
|
|
33
|
-
|
|
34
|
-
The following order is used to determine the database connection:
|
|
35
|
-
1. Use the db_engine if provided
|
|
36
|
-
2. Use the db_url
|
|
37
|
-
3. Use the db_file
|
|
38
|
-
4. Create a new in-memory database
|
|
39
|
-
|
|
40
|
-
Args:
|
|
41
|
-
table_name: The name of the table to store Agent sessions.
|
|
42
|
-
db_url: The database URL to connect to.
|
|
43
|
-
db_file: The database file to connect to.
|
|
44
|
-
db_engine: The SQLAlchemy database engine to use.
|
|
45
|
-
"""
|
|
46
|
-
_engine: Optional[Engine] = db_engine
|
|
47
|
-
if _engine is None and db_url is not None:
|
|
48
|
-
_engine = create_engine(db_url)
|
|
49
|
-
elif _engine is None and db_file is not None:
|
|
50
|
-
# Use the db_file to create the engine
|
|
51
|
-
db_path = Path(db_file).resolve()
|
|
52
|
-
# Ensure the directory exists
|
|
53
|
-
db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
54
|
-
_engine = create_engine(f"sqlite:///{db_path}")
|
|
55
|
-
else:
|
|
56
|
-
_engine = create_engine("sqlite://")
|
|
57
|
-
|
|
58
|
-
if _engine is None:
|
|
59
|
-
raise ValueError("Must provide either db_url, db_file or db_engine")
|
|
60
|
-
|
|
61
|
-
# Database attributes
|
|
62
|
-
self.table_name: str = table_name
|
|
63
|
-
self.db_url: Optional[str] = db_url
|
|
64
|
-
self.db_engine: Engine = _engine
|
|
65
|
-
self.metadata: MetaData = MetaData()
|
|
66
|
-
self.inspector = inspect(self.db_engine)
|
|
67
|
-
|
|
68
|
-
# Table schema version
|
|
69
|
-
self.schema_version: int = schema_version
|
|
70
|
-
# Automatically upgrade schema if True
|
|
71
|
-
self.auto_upgrade_schema: bool = auto_upgrade_schema
|
|
72
|
-
|
|
73
|
-
# Database session
|
|
74
|
-
self.Session: sessionmaker[Session] = sessionmaker(bind=self.db_engine)
|
|
75
|
-
# Database table for storage
|
|
76
|
-
self.table: Table = self.get_table()
|
|
77
|
-
|
|
78
|
-
def get_table_v1(self) -> Table:
|
|
79
|
-
"""
|
|
80
|
-
Define the table schema for version 1.
|
|
81
|
-
|
|
82
|
-
Returns:
|
|
83
|
-
Table: SQLAlchemy Table object representing the schema.
|
|
84
|
-
"""
|
|
85
|
-
return Table(
|
|
86
|
-
self.table_name,
|
|
87
|
-
self.metadata,
|
|
88
|
-
# Session UUID: Primary Key
|
|
89
|
-
Column("session_id", String, primary_key=True),
|
|
90
|
-
# ID of the agent that this session is associated with
|
|
91
|
-
Column("agent_id", String),
|
|
92
|
-
# ID of the user interacting with this agent
|
|
93
|
-
Column("user_id", String),
|
|
94
|
-
# Agent Memory
|
|
95
|
-
Column("memory", sqlite.JSON),
|
|
96
|
-
# Agent Data
|
|
97
|
-
Column("agent_data", sqlite.JSON),
|
|
98
|
-
# Session Data
|
|
99
|
-
Column("session_data", sqlite.JSON),
|
|
100
|
-
# Extra Data stored with this agent
|
|
101
|
-
Column("extra_data", sqlite.JSON),
|
|
102
|
-
# The Unix timestamp of when this session was created.
|
|
103
|
-
Column("created_at", sqlite.INTEGER, default=lambda: int(time.time())),
|
|
104
|
-
# The Unix timestamp of when this session was last updated.
|
|
105
|
-
Column("updated_at", sqlite.INTEGER, onupdate=lambda: int(time.time())),
|
|
106
|
-
extend_existing=True,
|
|
107
|
-
sqlite_autoincrement=True,
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
def get_table(self) -> Table:
|
|
111
|
-
"""
|
|
112
|
-
Get the table schema based on the schema version.
|
|
113
|
-
|
|
114
|
-
Returns:
|
|
115
|
-
Table: SQLAlchemy Table object for the current schema version.
|
|
116
|
-
|
|
117
|
-
Raises:
|
|
118
|
-
ValueError: If an unsupported schema version is specified.
|
|
119
|
-
"""
|
|
120
|
-
if self.schema_version == 1:
|
|
121
|
-
return self.get_table_v1()
|
|
122
|
-
else:
|
|
123
|
-
raise ValueError(f"Unsupported schema version: {self.schema_version}")
|
|
124
|
-
|
|
125
|
-
def table_exists(self) -> bool:
|
|
126
|
-
"""
|
|
127
|
-
Check if the table exists in the database.
|
|
128
|
-
|
|
129
|
-
Returns:
|
|
130
|
-
bool: True if the table exists, False otherwise.
|
|
131
|
-
"""
|
|
132
|
-
logger.debug(f"Checking if table exists: {self.table.name}")
|
|
133
|
-
try:
|
|
134
|
-
return self.inspector.has_table(self.table.name)
|
|
135
|
-
except Exception as e:
|
|
136
|
-
logger.error(f"Error checking if table exists: {e}")
|
|
137
|
-
return False
|
|
138
|
-
|
|
139
|
-
def create(self) -> None:
|
|
140
|
-
"""
|
|
141
|
-
Create the table if it doesn't exist.
|
|
142
|
-
"""
|
|
143
|
-
if not self.table_exists():
|
|
144
|
-
logger.debug(f"Creating table: {self.table.name}")
|
|
145
|
-
self.table.create(self.db_engine, checkfirst=True)
|
|
146
|
-
|
|
147
|
-
def read(self, session_id: str, user_id: Optional[str] = None) -> Optional[AgentSession]:
|
|
148
|
-
"""
|
|
149
|
-
Read an AgentSession from the database.
|
|
150
|
-
|
|
151
|
-
Args:
|
|
152
|
-
session_id (str): ID of the session to read.
|
|
153
|
-
user_id (Optional[str]): User ID to filter by. Defaults to None.
|
|
154
|
-
|
|
155
|
-
Returns:
|
|
156
|
-
Optional[AgentSession]: AgentSession object if found, None otherwise.
|
|
157
|
-
"""
|
|
158
|
-
try:
|
|
159
|
-
with self.Session() as sess:
|
|
160
|
-
stmt = select(self.table).where(self.table.c.session_id == session_id)
|
|
161
|
-
if user_id:
|
|
162
|
-
stmt = stmt.where(self.table.c.user_id == user_id)
|
|
163
|
-
result = sess.execute(stmt).fetchone()
|
|
164
|
-
return AgentSession.from_dict(result._mapping) if result is not None else None # type: ignore
|
|
165
|
-
except Exception as e:
|
|
166
|
-
logger.debug(f"Exception reading from table: {e}")
|
|
167
|
-
logger.debug(f"Table does not exist: {self.table.name}")
|
|
168
|
-
logger.debug("Creating table for future transactions")
|
|
169
|
-
self.create()
|
|
170
|
-
return None
|
|
171
|
-
|
|
172
|
-
def get_all_session_ids(self, user_id: Optional[str] = None, agent_id: Optional[str] = None) -> List[str]:
|
|
173
|
-
"""
|
|
174
|
-
Get all session IDs, optionally filtered by user_id and/or agent_id.
|
|
175
|
-
|
|
176
|
-
Args:
|
|
177
|
-
user_id (Optional[str]): The ID of the user to filter by.
|
|
178
|
-
agent_id (Optional[str]): The ID of the agent to filter by.
|
|
179
|
-
|
|
180
|
-
Returns:
|
|
181
|
-
List[str]: List of session IDs matching the criteria.
|
|
182
|
-
"""
|
|
183
|
-
try:
|
|
184
|
-
with self.Session() as sess, sess.begin():
|
|
185
|
-
# get all session_ids
|
|
186
|
-
stmt = select(self.table.c.session_id)
|
|
187
|
-
if user_id is not None:
|
|
188
|
-
stmt = stmt.where(self.table.c.user_id == user_id)
|
|
189
|
-
if agent_id is not None:
|
|
190
|
-
stmt = stmt.where(self.table.c.agent_id == agent_id)
|
|
191
|
-
# order by created_at desc
|
|
192
|
-
stmt = stmt.order_by(self.table.c.created_at.desc())
|
|
193
|
-
# execute query
|
|
194
|
-
rows = sess.execute(stmt).fetchall()
|
|
195
|
-
return [row[0] for row in rows] if rows is not None else []
|
|
196
|
-
except Exception as e:
|
|
197
|
-
logger.debug(f"Exception reading from table: {e}")
|
|
198
|
-
logger.debug(f"Table does not exist: {self.table.name}")
|
|
199
|
-
logger.debug("Creating table for future transactions")
|
|
200
|
-
self.create()
|
|
201
|
-
return []
|
|
202
|
-
|
|
203
|
-
def get_all_sessions(self, user_id: Optional[str] = None, agent_id: Optional[str] = None) -> List[AgentSession]:
|
|
204
|
-
"""
|
|
205
|
-
Get all sessions, optionally filtered by user_id and/or agent_id.
|
|
206
|
-
|
|
207
|
-
Args:
|
|
208
|
-
user_id (Optional[str]): The ID of the user to filter by.
|
|
209
|
-
agent_id (Optional[str]): The ID of the agent to filter by.
|
|
210
|
-
|
|
211
|
-
Returns:
|
|
212
|
-
List[AgentSession]: List of AgentSession objects matching the criteria.
|
|
213
|
-
"""
|
|
214
|
-
try:
|
|
215
|
-
with self.Session() as sess, sess.begin():
|
|
216
|
-
# get all sessions
|
|
217
|
-
stmt = select(self.table)
|
|
218
|
-
if user_id is not None:
|
|
219
|
-
stmt = stmt.where(self.table.c.user_id == user_id)
|
|
220
|
-
if agent_id is not None:
|
|
221
|
-
stmt = stmt.where(self.table.c.agent_id == agent_id)
|
|
222
|
-
# order by created_at desc
|
|
223
|
-
stmt = stmt.order_by(self.table.c.created_at.desc())
|
|
224
|
-
# execute query
|
|
225
|
-
rows = sess.execute(stmt).fetchall()
|
|
226
|
-
return [AgentSession.from_dict(row._mapping) for row in rows] if rows is not None else [] # type: ignore
|
|
227
|
-
except Exception as e:
|
|
228
|
-
logger.debug(f"Exception reading from table: {e}")
|
|
229
|
-
logger.debug(f"Table does not exist: {self.table.name}")
|
|
230
|
-
logger.debug("Creating table for future transactions")
|
|
231
|
-
self.create()
|
|
232
|
-
return []
|
|
233
|
-
|
|
234
|
-
def upsert(self, session: AgentSession, create_and_retry: bool = True) -> Optional[AgentSession]:
|
|
235
|
-
"""
|
|
236
|
-
Insert or update an AgentSession in the database.
|
|
237
|
-
|
|
238
|
-
Args:
|
|
239
|
-
session (AgentSession): The session data to upsert.
|
|
240
|
-
create_and_retry (bool): Retry upsert if table does not exist.
|
|
241
|
-
|
|
242
|
-
Returns:
|
|
243
|
-
Optional[AgentSession]: The upserted AgentSession, or None if operation failed.
|
|
244
|
-
"""
|
|
245
|
-
try:
|
|
246
|
-
with self.Session() as sess, sess.begin():
|
|
247
|
-
# Create an insert statement
|
|
248
|
-
stmt = sqlite.insert(self.table).values(
|
|
249
|
-
session_id=session.session_id,
|
|
250
|
-
agent_id=session.agent_id,
|
|
251
|
-
user_id=session.user_id,
|
|
252
|
-
memory=session.memory,
|
|
253
|
-
agent_data=session.agent_data,
|
|
254
|
-
session_data=session.session_data,
|
|
255
|
-
extra_data=session.extra_data,
|
|
256
|
-
)
|
|
257
|
-
|
|
258
|
-
# Define the upsert if the session_id already exists
|
|
259
|
-
# See: https://docs.sqlalchemy.org/en/20/dialects/sqlite.html#insert-on-conflict-upsert
|
|
260
|
-
stmt = stmt.on_conflict_do_update(
|
|
261
|
-
index_elements=["session_id"],
|
|
262
|
-
set_=dict(
|
|
263
|
-
agent_id=session.agent_id,
|
|
264
|
-
user_id=session.user_id,
|
|
265
|
-
memory=session.memory,
|
|
266
|
-
agent_data=session.agent_data,
|
|
267
|
-
session_data=session.session_data,
|
|
268
|
-
extra_data=session.extra_data,
|
|
269
|
-
updated_at=int(time.time()),
|
|
270
|
-
), # The updated value for each column
|
|
271
|
-
)
|
|
272
|
-
|
|
273
|
-
sess.execute(stmt)
|
|
274
|
-
except Exception as e:
|
|
275
|
-
logger.debug(f"Exception upserting into table: {e}")
|
|
276
|
-
if create_and_retry and not self.table_exists():
|
|
277
|
-
logger.debug(f"Table does not exist: {self.table.name}")
|
|
278
|
-
logger.debug("Creating table and retrying upsert")
|
|
279
|
-
self.create()
|
|
280
|
-
return self.upsert(session, create_and_retry=False)
|
|
281
|
-
return None
|
|
282
|
-
return self.read(session_id=session.session_id)
|
|
283
|
-
|
|
284
|
-
def delete_session(self, session_id: Optional[str] = None):
|
|
285
|
-
"""
|
|
286
|
-
Delete a workflow session from the database.
|
|
287
|
-
|
|
288
|
-
Args:
|
|
289
|
-
session_id (Optional[str]): The ID of the session to delete.
|
|
290
|
-
|
|
291
|
-
Raises:
|
|
292
|
-
ValueError: If session_id is not provided.
|
|
293
|
-
"""
|
|
294
|
-
if session_id is None:
|
|
295
|
-
logger.warning("No session_id provided for deletion.")
|
|
296
|
-
return
|
|
297
|
-
|
|
298
|
-
try:
|
|
299
|
-
with self.Session() as sess, sess.begin():
|
|
300
|
-
# Delete the session with the given session_id
|
|
301
|
-
delete_stmt = self.table.delete().where(self.table.c.session_id == session_id)
|
|
302
|
-
result = sess.execute(delete_stmt)
|
|
303
|
-
if result.rowcount == 0:
|
|
304
|
-
logger.debug(f"No session found with session_id: {session_id}")
|
|
305
|
-
else:
|
|
306
|
-
logger.debug(f"Successfully deleted session with session_id: {session_id}")
|
|
307
|
-
except Exception as e:
|
|
308
|
-
logger.error(f"Error deleting session: {e}")
|
|
309
|
-
|
|
310
|
-
def drop(self) -> None:
|
|
311
|
-
"""
|
|
312
|
-
Drop the table from the database if it exists.
|
|
313
|
-
"""
|
|
314
|
-
if self.table_exists():
|
|
315
|
-
logger.debug(f"Deleting table: {self.table_name}")
|
|
316
|
-
self.table.drop(self.db_engine)
|
|
317
|
-
|
|
318
|
-
def upgrade_schema(self) -> None:
|
|
319
|
-
"""
|
|
320
|
-
Upgrade the schema of the workflow storage table.
|
|
321
|
-
This method is currently a placeholder and does not perform any actions.
|
|
322
|
-
"""
|
|
323
|
-
pass
|
|
324
|
-
|
|
325
|
-
def __deepcopy__(self, memo):
|
|
326
|
-
"""
|
|
327
|
-
Create a deep copy of the SqliteAgentStorage instance, handling unpickleable attributes.
|
|
328
|
-
|
|
329
|
-
Args:
|
|
330
|
-
memo (dict): A dictionary of objects already copied during the current copying pass.
|
|
331
|
-
|
|
332
|
-
Returns:
|
|
333
|
-
SqliteAgentStorage: A deep-copied instance of SqliteAgentStorage.
|
|
334
|
-
"""
|
|
335
|
-
from copy import deepcopy
|
|
336
|
-
|
|
337
|
-
# Create a new instance without calling __init__
|
|
338
|
-
cls = self.__class__
|
|
339
|
-
copied_obj = cls.__new__(cls)
|
|
340
|
-
memo[id(self)] = copied_obj
|
|
341
|
-
|
|
342
|
-
# Deep copy attributes
|
|
343
|
-
for k, v in self.__dict__.items():
|
|
344
|
-
if k in {"metadata", "table", "inspector"}:
|
|
345
|
-
continue
|
|
346
|
-
# Reuse db_engine and Session without copying
|
|
347
|
-
elif k in {"db_engine", "Session"}:
|
|
348
|
-
setattr(copied_obj, k, v)
|
|
349
|
-
else:
|
|
350
|
-
setattr(copied_obj, k, deepcopy(v, memo))
|
|
351
|
-
|
|
352
|
-
# Recreate metadata and table for the copied instance
|
|
353
|
-
copied_obj.metadata = MetaData()
|
|
354
|
-
copied_obj.inspector = inspect(copied_obj.db_engine)
|
|
355
|
-
copied_obj.table = copied_obj.get_table()
|
|
356
|
-
|
|
357
|
-
return copied_obj
|