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/tools/lumalab.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import time
|
|
2
2
|
import uuid
|
|
3
3
|
from os import getenv
|
|
4
|
-
from typing import Any, Dict, Literal, Optional, TypedDict
|
|
4
|
+
from typing import Any, Dict, List, Literal, Optional, TypedDict
|
|
5
5
|
|
|
6
6
|
from agno.agent import Agent
|
|
7
|
-
from agno.media import
|
|
7
|
+
from agno.media import Video
|
|
8
8
|
from agno.tools import Toolkit
|
|
9
|
-
from agno.
|
|
9
|
+
from agno.tools.function import ToolResult
|
|
10
|
+
from agno.utils.log import log_info, logger
|
|
10
11
|
|
|
11
12
|
try:
|
|
12
13
|
from lumaai import LumaAI # type: ignore
|
|
@@ -30,9 +31,11 @@ class LumaLabTools(Toolkit):
|
|
|
30
31
|
wait_for_completion: bool = True,
|
|
31
32
|
poll_interval: int = 3,
|
|
32
33
|
max_wait_time: int = 300, # 5 minutes
|
|
34
|
+
enable_generate_video: bool = True,
|
|
35
|
+
enable_image_to_video: bool = True,
|
|
36
|
+
all: bool = False,
|
|
37
|
+
**kwargs,
|
|
33
38
|
):
|
|
34
|
-
super().__init__(name="luma_lab")
|
|
35
|
-
|
|
36
39
|
self.wait_for_completion = wait_for_completion
|
|
37
40
|
self.poll_interval = poll_interval
|
|
38
41
|
self.max_wait_time = max_wait_time
|
|
@@ -42,8 +45,14 @@ class LumaLabTools(Toolkit):
|
|
|
42
45
|
logger.error("LUMAAI_API_KEY not set. Please set the LUMAAI_API_KEY environment variable.")
|
|
43
46
|
|
|
44
47
|
self.client = LumaAI(auth_token=self.api_key)
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
|
|
49
|
+
tools: List[Any] = []
|
|
50
|
+
if all or enable_generate_video:
|
|
51
|
+
tools.append(self.generate_video)
|
|
52
|
+
if all or enable_image_to_video:
|
|
53
|
+
tools.append(self.image_to_video)
|
|
54
|
+
|
|
55
|
+
super().__init__(name="luma_lab", tools=tools, **kwargs)
|
|
47
56
|
|
|
48
57
|
def image_to_video(
|
|
49
58
|
self,
|
|
@@ -53,7 +62,7 @@ class LumaLabTools(Toolkit):
|
|
|
53
62
|
end_image_url: Optional[str] = None,
|
|
54
63
|
loop: bool = False,
|
|
55
64
|
aspect_ratio: Literal["1:1", "16:9", "9:16", "4:3", "3:4", "21:9", "9:21"] = "16:9",
|
|
56
|
-
) ->
|
|
65
|
+
) -> ToolResult:
|
|
57
66
|
"""Generate a video from one or two images with a prompt.
|
|
58
67
|
|
|
59
68
|
Args:
|
|
@@ -65,7 +74,7 @@ class LumaLabTools(Toolkit):
|
|
|
65
74
|
aspect_ratio: Aspect ratio of the output video
|
|
66
75
|
|
|
67
76
|
Returns:
|
|
68
|
-
|
|
77
|
+
ToolResult: A ToolResult containing the generated video or error message.
|
|
69
78
|
"""
|
|
70
79
|
|
|
71
80
|
try:
|
|
@@ -87,33 +96,36 @@ class LumaLabTools(Toolkit):
|
|
|
87
96
|
video_id = str(uuid.uuid4())
|
|
88
97
|
|
|
89
98
|
if not self.wait_for_completion:
|
|
90
|
-
return "Async generation unsupported"
|
|
99
|
+
return ToolResult(content="Async generation unsupported")
|
|
91
100
|
|
|
92
101
|
# Poll for completion
|
|
93
102
|
seconds_waited = 0
|
|
94
103
|
while seconds_waited < self.max_wait_time:
|
|
95
104
|
if not generation or not generation.id:
|
|
96
|
-
return "Failed to get generation ID"
|
|
105
|
+
return ToolResult(content="Failed to get generation ID")
|
|
97
106
|
|
|
98
107
|
generation = self.client.generations.get(generation.id)
|
|
99
108
|
|
|
100
109
|
if generation.state == "completed" and generation.assets:
|
|
101
110
|
video_url = generation.assets.video
|
|
102
111
|
if video_url:
|
|
103
|
-
|
|
104
|
-
return
|
|
112
|
+
video_artifact = Video(id=video_id, url=video_url, eta="completed")
|
|
113
|
+
return ToolResult(
|
|
114
|
+
content=f"Video generated successfully: {video_url}",
|
|
115
|
+
videos=[video_artifact],
|
|
116
|
+
)
|
|
105
117
|
elif generation.state == "failed":
|
|
106
|
-
return f"Generation failed: {generation.failure_reason}"
|
|
118
|
+
return ToolResult(content=f"Generation failed: {generation.failure_reason}")
|
|
107
119
|
|
|
108
|
-
|
|
120
|
+
log_info(f"Generation in progress... State: {generation.state}")
|
|
109
121
|
time.sleep(self.poll_interval)
|
|
110
122
|
seconds_waited += self.poll_interval
|
|
111
123
|
|
|
112
|
-
return f"Video generation timed out after {self.max_wait_time} seconds"
|
|
124
|
+
return ToolResult(content=f"Video generation timed out after {self.max_wait_time} seconds")
|
|
113
125
|
|
|
114
126
|
except Exception as e:
|
|
115
127
|
logger.error(f"Failed to generate video: {e}")
|
|
116
|
-
return f"Error: {e}"
|
|
128
|
+
return ToolResult(content=f"Error: {e}")
|
|
117
129
|
|
|
118
130
|
def generate_video(
|
|
119
131
|
self,
|
|
@@ -122,7 +134,7 @@ class LumaLabTools(Toolkit):
|
|
|
122
134
|
loop: bool = False,
|
|
123
135
|
aspect_ratio: Literal["1:1", "16:9", "9:16", "4:3", "3:4", "21:9", "9:21"] = "16:9",
|
|
124
136
|
keyframes: Optional[Dict[str, Dict[str, str]]] = None,
|
|
125
|
-
) ->
|
|
137
|
+
) -> ToolResult:
|
|
126
138
|
"""Use this function to generate a video given a prompt."""
|
|
127
139
|
|
|
128
140
|
try:
|
|
@@ -139,30 +151,33 @@ class LumaLabTools(Toolkit):
|
|
|
139
151
|
|
|
140
152
|
video_id = str(uuid.uuid4())
|
|
141
153
|
if not self.wait_for_completion:
|
|
142
|
-
return "Async generation unsupported"
|
|
154
|
+
return ToolResult(content="Async generation unsupported")
|
|
143
155
|
|
|
144
156
|
# Poll for completion
|
|
145
157
|
seconds_waited = 0
|
|
146
158
|
while seconds_waited < self.max_wait_time:
|
|
147
159
|
if not generation or not generation.id:
|
|
148
|
-
return "Failed to get generation ID"
|
|
160
|
+
return ToolResult(content="Failed to get generation ID")
|
|
149
161
|
|
|
150
162
|
generation = self.client.generations.get(generation.id)
|
|
151
163
|
|
|
152
164
|
if generation.state == "completed" and generation.assets:
|
|
153
165
|
video_url = generation.assets.video
|
|
154
166
|
if video_url:
|
|
155
|
-
|
|
156
|
-
return
|
|
167
|
+
video_artifact = Video(id=video_id, url=video_url, state="completed")
|
|
168
|
+
return ToolResult(
|
|
169
|
+
content=f"Video generated successfully: {video_url}",
|
|
170
|
+
videos=[video_artifact],
|
|
171
|
+
)
|
|
157
172
|
elif generation.state == "failed":
|
|
158
|
-
return f"Generation failed: {generation.failure_reason}"
|
|
173
|
+
return ToolResult(content=f"Generation failed: {generation.failure_reason}")
|
|
159
174
|
|
|
160
|
-
|
|
175
|
+
log_info(f"Generation in progress... State: {generation.state}")
|
|
161
176
|
time.sleep(self.poll_interval)
|
|
162
177
|
seconds_waited += self.poll_interval
|
|
163
178
|
|
|
164
|
-
return f"Video generation timed out after {self.max_wait_time} seconds"
|
|
179
|
+
return ToolResult(content=f"Video generation timed out after {self.max_wait_time} seconds")
|
|
165
180
|
|
|
166
181
|
except Exception as e:
|
|
167
182
|
logger.error(f"Failed to generate video: {e}")
|
|
168
|
-
return f"Error: {e}"
|
|
183
|
+
return ToolResult(content=f"Error: {e}")
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from agno.tools.mcp.mcp import MCPTools
|
|
2
|
+
from agno.tools.mcp.multi_mcp import MultiMCPTools
|
|
3
|
+
from agno.tools.mcp.params import SSEClientParams, StreamableHTTPClientParams
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"MCPTools",
|
|
7
|
+
"MultiMCPTools",
|
|
8
|
+
"StreamableHTTPClientParams",
|
|
9
|
+
"SSEClientParams",
|
|
10
|
+
]
|
agno/tools/mcp/mcp.py
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import weakref
|
|
2
|
+
from dataclasses import asdict
|
|
3
|
+
from datetime import timedelta
|
|
4
|
+
from typing import Any, Literal, Optional, Union
|
|
5
|
+
|
|
6
|
+
from agno.tools import Toolkit
|
|
7
|
+
from agno.tools.function import Function
|
|
8
|
+
from agno.tools.mcp.params import SSEClientParams, StreamableHTTPClientParams
|
|
9
|
+
from agno.utils.log import log_debug, log_error, log_info
|
|
10
|
+
from agno.utils.mcp import get_entrypoint_for_tool, prepare_command
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from mcp import ClientSession, StdioServerParameters
|
|
14
|
+
from mcp.client.sse import sse_client
|
|
15
|
+
from mcp.client.stdio import get_default_environment, stdio_client
|
|
16
|
+
from mcp.client.streamable_http import streamablehttp_client
|
|
17
|
+
except (ImportError, ModuleNotFoundError):
|
|
18
|
+
raise ImportError("`mcp` not installed. Please install using `pip install mcp`")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class MCPTools(Toolkit):
|
|
22
|
+
"""
|
|
23
|
+
A toolkit for integrating Model Context Protocol (MCP) servers with Agno agents.
|
|
24
|
+
This allows agents to access tools, resources, and prompts exposed by MCP servers.
|
|
25
|
+
|
|
26
|
+
Can be used in three ways:
|
|
27
|
+
1. Direct initialization with a ClientSession
|
|
28
|
+
2. As an async context manager with StdioServerParameters
|
|
29
|
+
3. As an async context manager with SSE or Streamable HTTP client parameters
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
command: Optional[str] = None,
|
|
35
|
+
*,
|
|
36
|
+
url: Optional[str] = None,
|
|
37
|
+
env: Optional[dict[str, str]] = None,
|
|
38
|
+
transport: Literal["stdio", "sse", "streamable-http"] = "stdio",
|
|
39
|
+
server_params: Optional[Union[StdioServerParameters, SSEClientParams, StreamableHTTPClientParams]] = None,
|
|
40
|
+
session: Optional[ClientSession] = None,
|
|
41
|
+
timeout_seconds: int = 10,
|
|
42
|
+
client=None,
|
|
43
|
+
include_tools: Optional[list[str]] = None,
|
|
44
|
+
exclude_tools: Optional[list[str]] = None,
|
|
45
|
+
refresh_connection: bool = False,
|
|
46
|
+
tool_name_prefix: Optional[str] = None,
|
|
47
|
+
**kwargs,
|
|
48
|
+
):
|
|
49
|
+
"""
|
|
50
|
+
Initialize the MCP toolkit.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
session: An initialized MCP ClientSession connected to an MCP server
|
|
54
|
+
server_params: Parameters for creating a new session
|
|
55
|
+
command: The command to run to start the server. Should be used in conjunction with env.
|
|
56
|
+
url: The URL endpoint for SSE or Streamable HTTP connection when transport is "sse" or "streamable-http".
|
|
57
|
+
env: The environment variables to pass to the server. Should be used in conjunction with command.
|
|
58
|
+
client: The underlying MCP client (optional, used to prevent garbage collection)
|
|
59
|
+
timeout_seconds: Read timeout in seconds for the MCP client
|
|
60
|
+
include_tools: Optional list of tool names to include (if None, includes all)
|
|
61
|
+
exclude_tools: Optional list of tool names to exclude (if None, excludes none)
|
|
62
|
+
transport: The transport protocol to use, either "stdio" or "sse" or "streamable-http"
|
|
63
|
+
refresh_connection: If True, the connection and tools will be refreshed on each run
|
|
64
|
+
"""
|
|
65
|
+
super().__init__(name="MCPTools", **kwargs)
|
|
66
|
+
|
|
67
|
+
if transport == "sse":
|
|
68
|
+
log_info("SSE as a standalone transport is deprecated. Please use Streamable HTTP instead.")
|
|
69
|
+
|
|
70
|
+
# Set these after `__init__` to bypass the `_check_tools_filters`
|
|
71
|
+
# because tools are not available until `initialize()` is called.
|
|
72
|
+
self.include_tools = include_tools
|
|
73
|
+
self.exclude_tools = exclude_tools
|
|
74
|
+
self.refresh_connection = refresh_connection
|
|
75
|
+
self.tool_name_prefix = tool_name_prefix
|
|
76
|
+
|
|
77
|
+
if session is None and server_params is None:
|
|
78
|
+
if transport == "sse" and url is None:
|
|
79
|
+
raise ValueError("One of 'url' or 'server_params' parameters must be provided when using SSE transport")
|
|
80
|
+
if transport == "stdio" and command is None:
|
|
81
|
+
raise ValueError(
|
|
82
|
+
"One of 'command' or 'server_params' parameters must be provided when using stdio transport"
|
|
83
|
+
)
|
|
84
|
+
if transport == "streamable-http" and url is None:
|
|
85
|
+
raise ValueError(
|
|
86
|
+
"One of 'url' or 'server_params' parameters must be provided when using Streamable HTTP transport"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Ensure the received server_params are valid for the given transport
|
|
90
|
+
if server_params is not None:
|
|
91
|
+
if transport == "sse":
|
|
92
|
+
if not isinstance(server_params, SSEClientParams):
|
|
93
|
+
raise ValueError(
|
|
94
|
+
"If using the SSE transport, server_params must be an instance of SSEClientParams."
|
|
95
|
+
)
|
|
96
|
+
elif transport == "stdio":
|
|
97
|
+
if not isinstance(server_params, StdioServerParameters):
|
|
98
|
+
raise ValueError(
|
|
99
|
+
"If using the stdio transport, server_params must be an instance of StdioServerParameters."
|
|
100
|
+
)
|
|
101
|
+
elif transport == "streamable-http":
|
|
102
|
+
if not isinstance(server_params, StreamableHTTPClientParams):
|
|
103
|
+
raise ValueError(
|
|
104
|
+
"If using the streamable-http transport, server_params must be an instance of StreamableHTTPClientParams."
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
self.timeout_seconds = timeout_seconds
|
|
108
|
+
self.session: Optional[ClientSession] = session
|
|
109
|
+
self.server_params: Optional[Union[StdioServerParameters, SSEClientParams, StreamableHTTPClientParams]] = (
|
|
110
|
+
server_params
|
|
111
|
+
)
|
|
112
|
+
self.transport = transport
|
|
113
|
+
self.url = url
|
|
114
|
+
|
|
115
|
+
# Merge provided env with system env
|
|
116
|
+
if env is not None:
|
|
117
|
+
env = {
|
|
118
|
+
**get_default_environment(),
|
|
119
|
+
**env,
|
|
120
|
+
}
|
|
121
|
+
else:
|
|
122
|
+
env = get_default_environment()
|
|
123
|
+
|
|
124
|
+
if command is not None and transport not in ["sse", "streamable-http"]:
|
|
125
|
+
parts = prepare_command(command)
|
|
126
|
+
cmd = parts[0]
|
|
127
|
+
arguments = parts[1:] if len(parts) > 1 else []
|
|
128
|
+
self.server_params = StdioServerParameters(command=cmd, args=arguments, env=env)
|
|
129
|
+
|
|
130
|
+
self._client = client
|
|
131
|
+
|
|
132
|
+
self._initialized = False
|
|
133
|
+
self._connection_task = None
|
|
134
|
+
self._active_contexts: list[Any] = []
|
|
135
|
+
self._context = None
|
|
136
|
+
self._session_context = None
|
|
137
|
+
|
|
138
|
+
def cleanup():
|
|
139
|
+
"""Cancel active connections"""
|
|
140
|
+
if self._connection_task and not self._connection_task.done():
|
|
141
|
+
self._connection_task.cancel()
|
|
142
|
+
|
|
143
|
+
# Setup cleanup logic before the instance is garbage collected
|
|
144
|
+
self._cleanup_finalizer = weakref.finalize(self, cleanup)
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def initialized(self) -> bool:
|
|
148
|
+
return self._initialized
|
|
149
|
+
|
|
150
|
+
async def is_alive(self) -> bool:
|
|
151
|
+
if self.session is None:
|
|
152
|
+
return False
|
|
153
|
+
try:
|
|
154
|
+
await self.session.send_ping()
|
|
155
|
+
return True
|
|
156
|
+
except (RuntimeError, BaseException):
|
|
157
|
+
return False
|
|
158
|
+
|
|
159
|
+
async def connect(self, force: bool = False):
|
|
160
|
+
"""Initialize a MCPTools instance and connect to the contextual MCP server"""
|
|
161
|
+
|
|
162
|
+
if force:
|
|
163
|
+
# Clean up the session and context so we force a new connection
|
|
164
|
+
self.session = None
|
|
165
|
+
self._context = None
|
|
166
|
+
self._session_context = None
|
|
167
|
+
self._initialized = False
|
|
168
|
+
self._connection_task = None
|
|
169
|
+
self._active_contexts = []
|
|
170
|
+
|
|
171
|
+
if self._initialized:
|
|
172
|
+
return
|
|
173
|
+
|
|
174
|
+
try:
|
|
175
|
+
await self._connect()
|
|
176
|
+
except (RuntimeError, BaseException) as e:
|
|
177
|
+
log_error(f"Failed to connect to {str(self)}: {e}")
|
|
178
|
+
|
|
179
|
+
async def _connect(self) -> None:
|
|
180
|
+
"""Connects to the MCP server and initializes the tools"""
|
|
181
|
+
|
|
182
|
+
if self._initialized:
|
|
183
|
+
return
|
|
184
|
+
|
|
185
|
+
if self.session is not None:
|
|
186
|
+
await self.initialize()
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
# Create a new studio session
|
|
190
|
+
if self.transport == "sse":
|
|
191
|
+
sse_params = asdict(self.server_params) if self.server_params is not None else {} # type: ignore
|
|
192
|
+
if "url" not in sse_params:
|
|
193
|
+
sse_params["url"] = self.url
|
|
194
|
+
self._context = sse_client(**sse_params) # type: ignore
|
|
195
|
+
client_timeout = min(self.timeout_seconds, sse_params.get("timeout", self.timeout_seconds))
|
|
196
|
+
|
|
197
|
+
# Create a new streamable HTTP session
|
|
198
|
+
elif self.transport == "streamable-http":
|
|
199
|
+
streamable_http_params = asdict(self.server_params) if self.server_params is not None else {} # type: ignore
|
|
200
|
+
if "url" not in streamable_http_params:
|
|
201
|
+
streamable_http_params["url"] = self.url
|
|
202
|
+
self._context = streamablehttp_client(**streamable_http_params) # type: ignore
|
|
203
|
+
params_timeout = streamable_http_params.get("timeout", self.timeout_seconds)
|
|
204
|
+
if isinstance(params_timeout, timedelta):
|
|
205
|
+
params_timeout = int(params_timeout.total_seconds())
|
|
206
|
+
client_timeout = min(self.timeout_seconds, params_timeout)
|
|
207
|
+
|
|
208
|
+
else:
|
|
209
|
+
if self.server_params is None:
|
|
210
|
+
raise ValueError("server_params must be provided when using stdio transport.")
|
|
211
|
+
self._context = stdio_client(self.server_params) # type: ignore
|
|
212
|
+
client_timeout = self.timeout_seconds
|
|
213
|
+
|
|
214
|
+
session_params = await self._context.__aenter__() # type: ignore
|
|
215
|
+
self._active_contexts.append(self._context)
|
|
216
|
+
read, write = session_params[0:2]
|
|
217
|
+
|
|
218
|
+
self._session_context = ClientSession(read, write, read_timeout_seconds=timedelta(seconds=client_timeout)) # type: ignore
|
|
219
|
+
self.session = await self._session_context.__aenter__() # type: ignore
|
|
220
|
+
self._active_contexts.append(self._session_context)
|
|
221
|
+
|
|
222
|
+
# Initialize with the new session
|
|
223
|
+
await self.initialize()
|
|
224
|
+
|
|
225
|
+
async def close(self) -> None:
|
|
226
|
+
"""Close the MCP connection and clean up resources"""
|
|
227
|
+
if not self._initialized:
|
|
228
|
+
return
|
|
229
|
+
|
|
230
|
+
try:
|
|
231
|
+
if self._session_context is not None:
|
|
232
|
+
await self._session_context.__aexit__(None, None, None)
|
|
233
|
+
self.session = None
|
|
234
|
+
self._session_context = None
|
|
235
|
+
|
|
236
|
+
if self._context is not None:
|
|
237
|
+
await self._context.__aexit__(None, None, None)
|
|
238
|
+
self._context = None
|
|
239
|
+
except (RuntimeError, BaseException) as e:
|
|
240
|
+
log_error(f"Failed to close MCP connection: {e}")
|
|
241
|
+
|
|
242
|
+
self._initialized = False
|
|
243
|
+
|
|
244
|
+
async def __aenter__(self) -> "MCPTools":
|
|
245
|
+
await self._connect()
|
|
246
|
+
return self
|
|
247
|
+
|
|
248
|
+
async def __aexit__(self, _exc_type, _exc_val, _exc_tb):
|
|
249
|
+
"""Exit the async context manager."""
|
|
250
|
+
if self._session_context is not None:
|
|
251
|
+
await self._session_context.__aexit__(_exc_type, _exc_val, _exc_tb)
|
|
252
|
+
self.session = None
|
|
253
|
+
self._session_context = None
|
|
254
|
+
|
|
255
|
+
if self._context is not None:
|
|
256
|
+
await self._context.__aexit__(_exc_type, _exc_val, _exc_tb)
|
|
257
|
+
self._context = None
|
|
258
|
+
|
|
259
|
+
self._initialized = False
|
|
260
|
+
|
|
261
|
+
async def build_tools(self) -> None:
|
|
262
|
+
"""Build the tools for the MCP toolkit"""
|
|
263
|
+
if self.session is None:
|
|
264
|
+
raise ValueError("Session is not initialized")
|
|
265
|
+
|
|
266
|
+
try:
|
|
267
|
+
# Get the list of tools from the MCP server
|
|
268
|
+
available_tools = await self.session.list_tools() # type: ignore
|
|
269
|
+
|
|
270
|
+
self._check_tools_filters(
|
|
271
|
+
available_tools=[tool.name for tool in available_tools.tools],
|
|
272
|
+
include_tools=self.include_tools,
|
|
273
|
+
exclude_tools=self.exclude_tools,
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
# Filter tools based on include/exclude lists
|
|
277
|
+
filtered_tools = []
|
|
278
|
+
for tool in available_tools.tools:
|
|
279
|
+
if self.exclude_tools and tool.name in self.exclude_tools:
|
|
280
|
+
continue
|
|
281
|
+
if self.include_tools is None or tool.name in self.include_tools:
|
|
282
|
+
filtered_tools.append(tool)
|
|
283
|
+
|
|
284
|
+
# Get tool name prefix if available
|
|
285
|
+
tool_name_prefix = ""
|
|
286
|
+
if self.tool_name_prefix is not None:
|
|
287
|
+
tool_name_prefix = self.tool_name_prefix + "_"
|
|
288
|
+
|
|
289
|
+
# Register the tools with the toolkit
|
|
290
|
+
for tool in filtered_tools:
|
|
291
|
+
try:
|
|
292
|
+
# Get an entrypoint for the tool
|
|
293
|
+
entrypoint = get_entrypoint_for_tool(tool, self.session) # type: ignore
|
|
294
|
+
# Create a Function for the tool
|
|
295
|
+
f = Function(
|
|
296
|
+
name=tool_name_prefix + tool.name,
|
|
297
|
+
description=tool.description,
|
|
298
|
+
parameters=tool.inputSchema,
|
|
299
|
+
entrypoint=entrypoint,
|
|
300
|
+
# Set skip_entrypoint_processing to True to avoid processing the entrypoint
|
|
301
|
+
skip_entrypoint_processing=True,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
# Register the Function with the toolkit
|
|
305
|
+
self.functions[f.name] = f
|
|
306
|
+
log_debug(f"Function: {f.name} registered with {self.name}")
|
|
307
|
+
except Exception as e:
|
|
308
|
+
log_error(f"Failed to register tool {tool.name}: {e}")
|
|
309
|
+
|
|
310
|
+
except (RuntimeError, BaseException) as e:
|
|
311
|
+
log_error(f"Failed to get tools for {str(self)}: {e}")
|
|
312
|
+
raise
|
|
313
|
+
|
|
314
|
+
async def initialize(self) -> None:
|
|
315
|
+
"""Initialize the MCP toolkit by getting available tools from the MCP server"""
|
|
316
|
+
if self._initialized:
|
|
317
|
+
return
|
|
318
|
+
|
|
319
|
+
try:
|
|
320
|
+
if self.session is None:
|
|
321
|
+
raise ValueError("Session is not initialized")
|
|
322
|
+
|
|
323
|
+
# Initialize the session if not already initialized
|
|
324
|
+
await self.session.initialize()
|
|
325
|
+
|
|
326
|
+
await self.build_tools()
|
|
327
|
+
|
|
328
|
+
self._initialized = True
|
|
329
|
+
|
|
330
|
+
except (RuntimeError, BaseException) as e:
|
|
331
|
+
log_error(f"Failed to initialize MCP toolkit: {e}")
|