agno 2.2.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 +51 -0
- agno/agent/agent.py +10405 -0
- agno/api/__init__.py +0 -0
- agno/api/agent.py +28 -0
- agno/api/api.py +40 -0
- agno/api/evals.py +22 -0
- agno/api/os.py +17 -0
- agno/api/routes.py +13 -0
- agno/api/schemas/__init__.py +9 -0
- agno/api/schemas/agent.py +16 -0
- agno/api/schemas/evals.py +16 -0
- agno/api/schemas/os.py +14 -0
- agno/api/schemas/response.py +6 -0
- agno/api/schemas/team.py +16 -0
- agno/api/schemas/utils.py +21 -0
- agno/api/schemas/workflows.py +16 -0
- agno/api/settings.py +53 -0
- agno/api/team.py +30 -0
- 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/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 +598 -0
- agno/db/dynamo/__init__.py +3 -0
- agno/db/dynamo/dynamo.py +2042 -0
- agno/db/dynamo/schemas.py +314 -0
- agno/db/dynamo/utils.py +743 -0
- agno/db/firestore/__init__.py +3 -0
- agno/db/firestore/firestore.py +1795 -0
- agno/db/firestore/schemas.py +140 -0
- agno/db/firestore/utils.py +376 -0
- agno/db/gcs_json/__init__.py +3 -0
- agno/db/gcs_json/gcs_json_db.py +1335 -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 +1160 -0
- agno/db/in_memory/utils.py +230 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1328 -0
- agno/db/json/utils.py +230 -0
- agno/db/migrations/__init__.py +0 -0
- agno/db/migrations/v1_to_v2.py +635 -0
- agno/db/mongo/__init__.py +17 -0
- agno/db/mongo/async_mongo.py +2026 -0
- agno/db/mongo/mongo.py +1982 -0
- agno/db/mongo/schemas.py +87 -0
- agno/db/mongo/utils.py +259 -0
- agno/db/mysql/__init__.py +3 -0
- agno/db/mysql/mysql.py +2308 -0
- agno/db/mysql/schemas.py +138 -0
- agno/db/mysql/utils.py +355 -0
- agno/db/postgres/__init__.py +4 -0
- agno/db/postgres/async_postgres.py +1927 -0
- agno/db/postgres/postgres.py +2260 -0
- agno/db/postgres/schemas.py +139 -0
- agno/db/postgres/utils.py +442 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +1660 -0
- agno/db/redis/schemas.py +123 -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 +33 -0
- agno/db/schemas/knowledge.py +40 -0
- agno/db/schemas/memory.py +46 -0
- agno/db/schemas/metrics.py +0 -0
- agno/db/singlestore/__init__.py +3 -0
- agno/db/singlestore/schemas.py +130 -0
- agno/db/singlestore/singlestore.py +2272 -0
- agno/db/singlestore/utils.py +384 -0
- agno/db/sqlite/__init__.py +4 -0
- agno/db/sqlite/async_sqlite.py +2293 -0
- agno/db/sqlite/schemas.py +133 -0
- agno/db/sqlite/sqlite.py +2288 -0
- agno/db/sqlite/utils.py +431 -0
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +309 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1353 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +116 -0
- agno/debug.py +18 -0
- agno/eval/__init__.py +14 -0
- agno/eval/accuracy.py +834 -0
- agno/eval/performance.py +773 -0
- agno/eval/reliability.py +306 -0
- agno/eval/utils.py +119 -0
- agno/exceptions.py +161 -0
- 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/integrations/__init__.py +0 -0
- agno/integrations/discord/__init__.py +3 -0
- agno/integrations/discord/client.py +203 -0
- agno/knowledge/__init__.py +5 -0
- agno/knowledge/chunking/__init__.py +0 -0
- agno/knowledge/chunking/agentic.py +79 -0
- agno/knowledge/chunking/document.py +91 -0
- agno/knowledge/chunking/fixed.py +57 -0
- agno/knowledge/chunking/markdown.py +151 -0
- agno/knowledge/chunking/recursive.py +63 -0
- agno/knowledge/chunking/row.py +39 -0
- agno/knowledge/chunking/semantic.py +86 -0
- agno/knowledge/chunking/strategy.py +165 -0
- agno/knowledge/content.py +74 -0
- agno/knowledge/document/__init__.py +5 -0
- agno/knowledge/document/base.py +58 -0
- agno/knowledge/embedder/__init__.py +5 -0
- agno/knowledge/embedder/aws_bedrock.py +343 -0
- agno/knowledge/embedder/azure_openai.py +210 -0
- agno/knowledge/embedder/base.py +23 -0
- agno/knowledge/embedder/cohere.py +323 -0
- agno/knowledge/embedder/fastembed.py +62 -0
- agno/knowledge/embedder/fireworks.py +13 -0
- 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/knowledge/embedder/together.py +13 -0
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +165 -0
- agno/knowledge/knowledge.py +1988 -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 +166 -0
- agno/knowledge/reader/docx_reader.py +82 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +292 -0
- agno/knowledge/reader/firecrawl_reader.py +201 -0
- agno/knowledge/reader/json_reader.py +87 -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 +194 -0
- agno/knowledge/reader/text_reader.py +115 -0
- agno/knowledge/reader/web_search_reader.py +372 -0
- agno/knowledge/reader/website_reader.py +455 -0
- agno/knowledge/reader/wikipedia_reader.py +59 -0
- agno/knowledge/reader/youtube_reader.py +78 -0
- agno/knowledge/remote_content/__init__.py +0 -0
- agno/knowledge/remote_content/remote_content.py +88 -0
- agno/knowledge/reranker/__init__.py +3 -0
- agno/knowledge/reranker/base.py +14 -0
- agno/knowledge/reranker/cohere.py +64 -0
- 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 +189 -0
- agno/media.py +462 -0
- agno/memory/__init__.py +3 -0
- agno/memory/manager.py +1327 -0
- agno/models/__init__.py +0 -0
- agno/models/aimlapi/__init__.py +5 -0
- agno/models/aimlapi/aimlapi.py +45 -0
- agno/models/anthropic/__init__.py +5 -0
- agno/models/anthropic/claude.py +757 -0
- agno/models/aws/__init__.py +15 -0
- agno/models/aws/bedrock.py +701 -0
- agno/models/aws/claude.py +378 -0
- agno/models/azure/__init__.py +18 -0
- agno/models/azure/ai_foundry.py +485 -0
- agno/models/azure/openai_chat.py +131 -0
- agno/models/base.py +2175 -0
- agno/models/cerebras/__init__.py +12 -0
- agno/models/cerebras/cerebras.py +501 -0
- agno/models/cerebras/cerebras_openai.py +112 -0
- agno/models/cohere/__init__.py +5 -0
- agno/models/cohere/chat.py +389 -0
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +57 -0
- agno/models/dashscope/__init__.py +5 -0
- agno/models/dashscope/dashscope.py +91 -0
- agno/models/deepinfra/__init__.py +5 -0
- agno/models/deepinfra/deepinfra.py +28 -0
- agno/models/deepseek/__init__.py +5 -0
- agno/models/deepseek/deepseek.py +61 -0
- agno/models/defaults.py +1 -0
- agno/models/fireworks/__init__.py +5 -0
- agno/models/fireworks/fireworks.py +26 -0
- agno/models/google/__init__.py +5 -0
- agno/models/google/gemini.py +1085 -0
- agno/models/groq/__init__.py +5 -0
- agno/models/groq/groq.py +556 -0
- agno/models/huggingface/__init__.py +5 -0
- agno/models/huggingface/huggingface.py +491 -0
- agno/models/ibm/__init__.py +5 -0
- agno/models/ibm/watsonx.py +422 -0
- agno/models/internlm/__init__.py +3 -0
- agno/models/internlm/internlm.py +26 -0
- agno/models/langdb/__init__.py +1 -0
- agno/models/langdb/langdb.py +48 -0
- agno/models/litellm/__init__.py +14 -0
- agno/models/litellm/chat.py +468 -0
- agno/models/litellm/litellm_openai.py +25 -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 +434 -0
- agno/models/meta/__init__.py +12 -0
- agno/models/meta/llama.py +475 -0
- agno/models/meta/llama_openai.py +78 -0
- agno/models/metrics.py +120 -0
- agno/models/mistral/__init__.py +5 -0
- agno/models/mistral/mistral.py +432 -0
- agno/models/nebius/__init__.py +3 -0
- agno/models/nebius/nebius.py +54 -0
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/__init__.py +5 -0
- agno/models/nvidia/nvidia.py +28 -0
- agno/models/ollama/__init__.py +5 -0
- agno/models/ollama/chat.py +441 -0
- agno/models/openai/__init__.py +9 -0
- agno/models/openai/chat.py +883 -0
- agno/models/openai/like.py +27 -0
- agno/models/openai/responses.py +1050 -0
- agno/models/openrouter/__init__.py +5 -0
- agno/models/openrouter/openrouter.py +66 -0
- agno/models/perplexity/__init__.py +5 -0
- agno/models/perplexity/perplexity.py +187 -0
- agno/models/portkey/__init__.py +3 -0
- agno/models/portkey/portkey.py +81 -0
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +52 -0
- agno/models/response.py +199 -0
- agno/models/sambanova/__init__.py +5 -0
- agno/models/sambanova/sambanova.py +28 -0
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +25 -0
- agno/models/together/__init__.py +5 -0
- agno/models/together/together.py +25 -0
- agno/models/utils.py +266 -0
- agno/models/vercel/__init__.py +3 -0
- agno/models/vercel/v0.py +26 -0
- agno/models/vertexai/__init__.py +0 -0
- agno/models/vertexai/claude.py +70 -0
- agno/models/vllm/__init__.py +3 -0
- agno/models/vllm/vllm.py +78 -0
- agno/models/xai/__init__.py +3 -0
- agno/models/xai/xai.py +113 -0
- agno/os/__init__.py +3 -0
- agno/os/app.py +876 -0
- agno/os/auth.py +57 -0
- agno/os/config.py +104 -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 +250 -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 +144 -0
- agno/os/interfaces/agui/utils.py +534 -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 +211 -0
- agno/os/interfaces/whatsapp/security.py +53 -0
- agno/os/interfaces/whatsapp/whatsapp.py +36 -0
- agno/os/mcp.py +292 -0
- agno/os/middleware/__init__.py +7 -0
- agno/os/middleware/jwt.py +233 -0
- agno/os/router.py +1763 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +430 -0
- agno/os/routers/evals/schemas.py +142 -0
- agno/os/routers/evals/utils.py +162 -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 +997 -0
- agno/os/routers/knowledge/schemas.py +178 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +515 -0
- agno/os/routers/memory/schemas.py +62 -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/schema.py +1055 -0
- agno/os/settings.py +43 -0
- agno/os/utils.py +630 -0
- agno/py.typed +0 -0
- agno/reasoning/__init__.py +0 -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 +63 -0
- agno/reasoning/ollama.py +67 -0
- agno/reasoning/openai.py +86 -0
- agno/reasoning/step.py +31 -0
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +787 -0
- agno/run/base.py +229 -0
- agno/run/cancel.py +81 -0
- agno/run/messages.py +32 -0
- agno/run/team.py +753 -0
- agno/run/workflow.py +708 -0
- agno/session/__init__.py +10 -0
- agno/session/agent.py +295 -0
- agno/session/summary.py +265 -0
- agno/session/team.py +392 -0
- agno/session/workflow.py +205 -0
- agno/team/__init__.py +37 -0
- agno/team/team.py +8793 -0
- agno/tools/__init__.py +10 -0
- agno/tools/agentql.py +120 -0
- agno/tools/airflow.py +69 -0
- agno/tools/api.py +122 -0
- agno/tools/apify.py +314 -0
- agno/tools/arxiv.py +127 -0
- agno/tools/aws_lambda.py +53 -0
- agno/tools/aws_ses.py +66 -0
- agno/tools/baidusearch.py +89 -0
- 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 +255 -0
- agno/tools/calculator.py +151 -0
- agno/tools/cartesia.py +187 -0
- agno/tools/clickup.py +244 -0
- agno/tools/confluence.py +240 -0
- agno/tools/crawl4ai.py +158 -0
- agno/tools/csv_toolkit.py +185 -0
- agno/tools/dalle.py +110 -0
- agno/tools/daytona.py +475 -0
- agno/tools/decorator.py +262 -0
- agno/tools/desi_vocal.py +108 -0
- agno/tools/discord.py +161 -0
- agno/tools/docker.py +716 -0
- agno/tools/duckdb.py +379 -0
- agno/tools/duckduckgo.py +91 -0
- agno/tools/e2b.py +703 -0
- agno/tools/eleven_labs.py +196 -0
- agno/tools/email.py +67 -0
- agno/tools/evm.py +129 -0
- agno/tools/exa.py +396 -0
- agno/tools/fal.py +127 -0
- agno/tools/file.py +240 -0
- agno/tools/file_generation.py +350 -0
- agno/tools/financial_datasets.py +288 -0
- agno/tools/firecrawl.py +143 -0
- agno/tools/function.py +1187 -0
- agno/tools/giphy.py +93 -0
- agno/tools/github.py +1760 -0
- agno/tools/gmail.py +922 -0
- agno/tools/google_bigquery.py +117 -0
- agno/tools/google_drive.py +270 -0
- agno/tools/google_maps.py +253 -0
- agno/tools/googlecalendar.py +674 -0
- agno/tools/googlesearch.py +98 -0
- agno/tools/googlesheets.py +377 -0
- agno/tools/hackernews.py +77 -0
- agno/tools/jina.py +101 -0
- agno/tools/jira.py +170 -0
- agno/tools/knowledge.py +218 -0
- agno/tools/linear.py +426 -0
- agno/tools/linkup.py +58 -0
- agno/tools/local_file_system.py +90 -0
- agno/tools/lumalab.py +183 -0
- 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/memori.py +339 -0
- agno/tools/memory.py +419 -0
- agno/tools/mlx_transcribe.py +139 -0
- agno/tools/models/__init__.py +0 -0
- 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 +195 -0
- agno/tools/moviepy_video.py +349 -0
- agno/tools/neo4j.py +134 -0
- agno/tools/newspaper.py +46 -0
- agno/tools/newspaper4k.py +93 -0
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +202 -0
- agno/tools/openbb.py +160 -0
- agno/tools/opencv.py +321 -0
- agno/tools/openweather.py +233 -0
- agno/tools/oxylabs.py +385 -0
- agno/tools/pandas.py +102 -0
- agno/tools/parallel.py +314 -0
- agno/tools/postgres.py +257 -0
- agno/tools/pubmed.py +188 -0
- agno/tools/python.py +205 -0
- agno/tools/reasoning.py +283 -0
- agno/tools/reddit.py +467 -0
- agno/tools/replicate.py +117 -0
- agno/tools/resend.py +62 -0
- agno/tools/scrapegraph.py +222 -0
- agno/tools/searxng.py +152 -0
- agno/tools/serpapi.py +116 -0
- agno/tools/serper.py +255 -0
- agno/tools/shell.py +53 -0
- agno/tools/slack.py +136 -0
- agno/tools/sleep.py +20 -0
- agno/tools/spider.py +116 -0
- agno/tools/sql.py +154 -0
- agno/tools/streamlit/__init__.py +0 -0
- agno/tools/streamlit/components.py +113 -0
- agno/tools/tavily.py +254 -0
- agno/tools/telegram.py +48 -0
- agno/tools/todoist.py +218 -0
- agno/tools/tool_registry.py +1 -0
- agno/tools/toolkit.py +146 -0
- agno/tools/trafilatura.py +388 -0
- agno/tools/trello.py +274 -0
- agno/tools/twilio.py +186 -0
- 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 +54 -0
- agno/tools/webtools.py +45 -0
- agno/tools/whatsapp.py +286 -0
- agno/tools/wikipedia.py +63 -0
- agno/tools/workflow.py +278 -0
- agno/tools/x.py +335 -0
- agno/tools/yfinance.py +257 -0
- agno/tools/youtube.py +184 -0
- agno/tools/zendesk.py +82 -0
- agno/tools/zep.py +454 -0
- agno/tools/zoom.py +382 -0
- agno/utils/__init__.py +0 -0
- agno/utils/agent.py +820 -0
- agno/utils/audio.py +49 -0
- agno/utils/certs.py +27 -0
- agno/utils/code_execution.py +11 -0
- agno/utils/common.py +132 -0
- agno/utils/dttm.py +13 -0
- agno/utils/enum.py +22 -0
- agno/utils/env.py +11 -0
- agno/utils/events.py +696 -0
- agno/utils/format_str.py +16 -0
- agno/utils/functions.py +166 -0
- agno/utils/gemini.py +426 -0
- agno/utils/hooks.py +57 -0
- agno/utils/http.py +74 -0
- agno/utils/json_schema.py +234 -0
- agno/utils/knowledge.py +36 -0
- agno/utils/location.py +19 -0
- agno/utils/log.py +255 -0
- agno/utils/mcp.py +214 -0
- agno/utils/media.py +352 -0
- agno/utils/merge_dict.py +41 -0
- agno/utils/message.py +118 -0
- agno/utils/models/__init__.py +0 -0
- agno/utils/models/ai_foundry.py +43 -0
- agno/utils/models/claude.py +358 -0
- agno/utils/models/cohere.py +87 -0
- agno/utils/models/llama.py +78 -0
- agno/utils/models/mistral.py +98 -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 +32 -0
- agno/utils/pprint.py +178 -0
- agno/utils/print_response/__init__.py +0 -0
- agno/utils/print_response/agent.py +842 -0
- agno/utils/print_response/team.py +1724 -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/response_iterator.py +17 -0
- agno/utils/safe_formatter.py +24 -0
- agno/utils/serialize.py +32 -0
- agno/utils/shell.py +22 -0
- agno/utils/streamlit.py +487 -0
- agno/utils/string.py +231 -0
- agno/utils/team.py +139 -0
- agno/utils/timer.py +41 -0
- agno/utils/tools.py +102 -0
- agno/utils/web.py +23 -0
- agno/utils/whatsapp.py +305 -0
- agno/utils/yaml_io.py +25 -0
- agno/vectordb/__init__.py +3 -0
- agno/vectordb/base.py +127 -0
- agno/vectordb/cassandra/__init__.py +5 -0
- agno/vectordb/cassandra/cassandra.py +501 -0
- agno/vectordb/cassandra/extra_param_mixin.py +11 -0
- agno/vectordb/cassandra/index.py +13 -0
- agno/vectordb/chroma/__init__.py +5 -0
- agno/vectordb/chroma/chromadb.py +929 -0
- agno/vectordb/clickhouse/__init__.py +9 -0
- agno/vectordb/clickhouse/clickhousedb.py +835 -0
- agno/vectordb/clickhouse/index.py +9 -0
- agno/vectordb/couchbase/__init__.py +3 -0
- agno/vectordb/couchbase/couchbase.py +1442 -0
- agno/vectordb/distance.py +7 -0
- agno/vectordb/lancedb/__init__.py +6 -0
- agno/vectordb/lancedb/lance_db.py +995 -0
- 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 +4 -0
- agno/vectordb/milvus/milvus.py +1182 -0
- agno/vectordb/mongodb/__init__.py +9 -0
- agno/vectordb/mongodb/mongodb.py +1417 -0
- agno/vectordb/pgvector/__init__.py +12 -0
- agno/vectordb/pgvector/index.py +23 -0
- agno/vectordb/pgvector/pgvector.py +1462 -0
- agno/vectordb/pineconedb/__init__.py +5 -0
- agno/vectordb/pineconedb/pineconedb.py +747 -0
- agno/vectordb/qdrant/__init__.py +5 -0
- agno/vectordb/qdrant/qdrant.py +1134 -0
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +694 -0
- agno/vectordb/search.py +7 -0
- agno/vectordb/singlestore/__init__.py +10 -0
- agno/vectordb/singlestore/index.py +41 -0
- agno/vectordb/singlestore/singlestore.py +763 -0
- agno/vectordb/surrealdb/__init__.py +3 -0
- agno/vectordb/surrealdb/surrealdb.py +699 -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 +1005 -0
- agno/workflow/__init__.py +23 -0
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +738 -0
- agno/workflow/loop.py +735 -0
- agno/workflow/parallel.py +824 -0
- agno/workflow/router.py +702 -0
- agno/workflow/step.py +1432 -0
- agno/workflow/steps.py +592 -0
- agno/workflow/types.py +520 -0
- agno/workflow/workflow.py +4321 -0
- agno-2.2.13.dist-info/METADATA +614 -0
- agno-2.2.13.dist-info/RECORD +575 -0
- agno-2.2.13.dist-info/WHEEL +5 -0
- agno-2.2.13.dist-info/licenses/LICENSE +201 -0
- agno-2.2.13.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Any, Callable, Dict, List, Optional, Set
|
|
3
|
+
|
|
4
|
+
from agno.tools import Toolkit
|
|
5
|
+
from agno.utils.log import log_debug, logger
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
from trafilatura import (
|
|
9
|
+
extract,
|
|
10
|
+
extract_metadata,
|
|
11
|
+
fetch_url,
|
|
12
|
+
html2txt,
|
|
13
|
+
)
|
|
14
|
+
from trafilatura.meta import reset_caches
|
|
15
|
+
|
|
16
|
+
# Import spider functionality
|
|
17
|
+
try:
|
|
18
|
+
from trafilatura.spider import focused_crawler
|
|
19
|
+
|
|
20
|
+
SPIDER_AVAILABLE = True
|
|
21
|
+
except ImportError:
|
|
22
|
+
SPIDER_AVAILABLE = False
|
|
23
|
+
logger.warning("Trafilatura spider module not available. Web crawling functionality will be disabled.")
|
|
24
|
+
|
|
25
|
+
except ImportError:
|
|
26
|
+
raise ImportError("`trafilatura` not installed. Please install using `pip install trafilatura`")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class TrafilaturaTools(Toolkit):
|
|
30
|
+
"""
|
|
31
|
+
TrafilaturaTools is a toolkit for web scraping and text extraction.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
output_format (str): Default output format for extractions. Options: 'txt', 'json', 'xml', 'markdown', 'csv', 'html', 'xmltei'.
|
|
35
|
+
include_comments (bool): Whether to extract comments along with main text by default.
|
|
36
|
+
include_tables (bool): Whether to include table content by default.
|
|
37
|
+
include_images (bool): Whether to include image information by default (experimental).
|
|
38
|
+
include_formatting (bool): Whether to preserve formatting by default.
|
|
39
|
+
include_links (bool): Whether to preserve links by default (experimental).
|
|
40
|
+
with_metadata (bool): Whether to include metadata in extractions by default.
|
|
41
|
+
favor_precision (bool): Whether to prefer precision over recall by default.
|
|
42
|
+
favor_recall (bool): Whether to prefer recall over precision by default.
|
|
43
|
+
target_language (Optional[str]): Default target language filter (ISO 639-1 format).
|
|
44
|
+
deduplicate (bool): Whether to remove duplicate segments by default.
|
|
45
|
+
max_tree_size (Optional[int]): Maximum tree size for processing.
|
|
46
|
+
max_crawl_urls (int): Maximum number of URLs to crawl per website.
|
|
47
|
+
max_known_urls (int): Maximum number of known URLs during crawling.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
output_format: str = "txt",
|
|
53
|
+
include_comments: bool = True,
|
|
54
|
+
include_tables: bool = True,
|
|
55
|
+
include_images: bool = False,
|
|
56
|
+
include_formatting: bool = False,
|
|
57
|
+
include_links: bool = False,
|
|
58
|
+
with_metadata: bool = False,
|
|
59
|
+
favor_precision: bool = False,
|
|
60
|
+
favor_recall: bool = False,
|
|
61
|
+
target_language: Optional[str] = None,
|
|
62
|
+
deduplicate: bool = False,
|
|
63
|
+
max_tree_size: Optional[int] = None,
|
|
64
|
+
max_crawl_urls: int = 10,
|
|
65
|
+
max_known_urls: int = 100000,
|
|
66
|
+
# Tool enable flags for <6 functions
|
|
67
|
+
enable_extract_text: bool = True,
|
|
68
|
+
enable_extract_metadata_only: bool = True,
|
|
69
|
+
enable_html_to_text: bool = True,
|
|
70
|
+
enable_extract_batch: bool = True,
|
|
71
|
+
enable_crawl_website: bool = True,
|
|
72
|
+
all: bool = False,
|
|
73
|
+
**kwargs,
|
|
74
|
+
):
|
|
75
|
+
self.output_format = output_format
|
|
76
|
+
self.include_comments = include_comments
|
|
77
|
+
self.include_tables = include_tables
|
|
78
|
+
self.include_images = include_images
|
|
79
|
+
self.include_formatting = include_formatting
|
|
80
|
+
self.include_links = include_links
|
|
81
|
+
self.with_metadata = with_metadata
|
|
82
|
+
self.favor_precision = favor_precision
|
|
83
|
+
self.favor_recall = favor_recall
|
|
84
|
+
self.target_language = target_language
|
|
85
|
+
self.deduplicate = deduplicate
|
|
86
|
+
self.max_tree_size = max_tree_size
|
|
87
|
+
self.max_crawl_urls = max_crawl_urls
|
|
88
|
+
self.max_known_urls = max_known_urls
|
|
89
|
+
|
|
90
|
+
tools: List[Callable] = []
|
|
91
|
+
if all or enable_extract_text:
|
|
92
|
+
tools.append(self.extract_text)
|
|
93
|
+
if all or enable_extract_metadata_only:
|
|
94
|
+
tools.append(self.extract_metadata_only)
|
|
95
|
+
if all or enable_html_to_text:
|
|
96
|
+
tools.append(self.html_to_text)
|
|
97
|
+
if all or enable_extract_batch:
|
|
98
|
+
tools.append(self.extract_batch)
|
|
99
|
+
|
|
100
|
+
if all or enable_crawl_website:
|
|
101
|
+
if not SPIDER_AVAILABLE:
|
|
102
|
+
logger.warning("Web crawling requested but spider module not available. Skipping crawler tool.")
|
|
103
|
+
else:
|
|
104
|
+
tools.append(self.crawl_website)
|
|
105
|
+
|
|
106
|
+
super().__init__(name="trafilatura_tools", tools=tools, **kwargs)
|
|
107
|
+
|
|
108
|
+
def _get_extraction_params(
|
|
109
|
+
self,
|
|
110
|
+
output_format: Optional[str] = None,
|
|
111
|
+
include_comments: Optional[bool] = None,
|
|
112
|
+
include_tables: Optional[bool] = None,
|
|
113
|
+
include_images: Optional[bool] = None,
|
|
114
|
+
include_formatting: Optional[bool] = None,
|
|
115
|
+
include_links: Optional[bool] = None,
|
|
116
|
+
with_metadata: Optional[bool] = None,
|
|
117
|
+
favor_precision: Optional[bool] = None,
|
|
118
|
+
favor_recall: Optional[bool] = None,
|
|
119
|
+
target_language: Optional[str] = None,
|
|
120
|
+
deduplicate: Optional[bool] = None,
|
|
121
|
+
max_tree_size: Optional[int] = None,
|
|
122
|
+
url_blacklist: Optional[Set[str]] = None,
|
|
123
|
+
author_blacklist: Optional[Set[str]] = None,
|
|
124
|
+
) -> Dict[str, Any]:
|
|
125
|
+
"""Helper method to build extraction parameters with fallbacks to instance defaults."""
|
|
126
|
+
return {
|
|
127
|
+
"output_format": output_format if output_format is not None else self.output_format,
|
|
128
|
+
"include_comments": include_comments if include_comments is not None else self.include_comments,
|
|
129
|
+
"include_tables": include_tables if include_tables is not None else self.include_tables,
|
|
130
|
+
"include_images": include_images if include_images is not None else self.include_images,
|
|
131
|
+
"include_formatting": include_formatting if include_formatting is not None else self.include_formatting,
|
|
132
|
+
"include_links": include_links if include_links is not None else self.include_links,
|
|
133
|
+
"with_metadata": with_metadata if with_metadata is not None else self.with_metadata,
|
|
134
|
+
"favor_precision": favor_precision if favor_precision is not None else self.favor_precision,
|
|
135
|
+
"favor_recall": favor_recall if favor_recall is not None else self.favor_recall,
|
|
136
|
+
"target_language": target_language if target_language is not None else self.target_language,
|
|
137
|
+
"deduplicate": deduplicate if deduplicate is not None else self.deduplicate,
|
|
138
|
+
"max_tree_size": max_tree_size if max_tree_size is not None else self.max_tree_size,
|
|
139
|
+
"url_blacklist": url_blacklist,
|
|
140
|
+
"author_blacklist": author_blacklist,
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
def extract_text(
|
|
144
|
+
self,
|
|
145
|
+
url: str,
|
|
146
|
+
output_format: Optional[str] = None,
|
|
147
|
+
) -> str:
|
|
148
|
+
"""
|
|
149
|
+
Extract main text content from a web page URL using Trafilatura.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
url (str): The URL to extract content from.
|
|
153
|
+
output_format (Optional[str]): Output format. Options: 'txt', 'json', 'xml', 'markdown', 'csv', 'html', 'xmltei'.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
str: Extracted content in the specified format, or error message if extraction fails.
|
|
157
|
+
"""
|
|
158
|
+
try:
|
|
159
|
+
log_debug(f"Extracting text from URL: {url}")
|
|
160
|
+
|
|
161
|
+
# Fetch the webpage content
|
|
162
|
+
html_content = fetch_url(url)
|
|
163
|
+
if not html_content:
|
|
164
|
+
return f"Error: Could not fetch content from URL: {url}"
|
|
165
|
+
|
|
166
|
+
# Get extraction parameters
|
|
167
|
+
params = self._get_extraction_params(output_format=output_format)
|
|
168
|
+
|
|
169
|
+
result = extract(html_content, url=url, **params)
|
|
170
|
+
|
|
171
|
+
if result is None:
|
|
172
|
+
return f"Error: Could not extract readable content from URL: {url}"
|
|
173
|
+
|
|
174
|
+
# Reset caches
|
|
175
|
+
reset_caches()
|
|
176
|
+
|
|
177
|
+
return result
|
|
178
|
+
|
|
179
|
+
except Exception as e:
|
|
180
|
+
logger.warning(f"Error extracting text from {url}: {e}")
|
|
181
|
+
return f"Error extracting text from {url}: {e}"
|
|
182
|
+
|
|
183
|
+
def extract_metadata_only(
|
|
184
|
+
self,
|
|
185
|
+
url: str,
|
|
186
|
+
as_json: bool = True,
|
|
187
|
+
) -> str:
|
|
188
|
+
"""
|
|
189
|
+
Extract only metadata from a web page URL.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
url (str): The URL to extract metadata from.
|
|
193
|
+
as_json (bool): Whether to return metadata as JSON string.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
str: Extracted metadata as JSON string or formatted text.
|
|
197
|
+
"""
|
|
198
|
+
try:
|
|
199
|
+
log_debug(f"Extracting metadata from URL: {url}")
|
|
200
|
+
|
|
201
|
+
# Fetch the webpage content
|
|
202
|
+
html_content = fetch_url(url)
|
|
203
|
+
if not html_content:
|
|
204
|
+
return f"Error: Could not fetch content from URL: {url}"
|
|
205
|
+
|
|
206
|
+
# Extract metadata
|
|
207
|
+
metadata_doc = extract_metadata(
|
|
208
|
+
html_content,
|
|
209
|
+
default_url=url,
|
|
210
|
+
extensive=True, # default
|
|
211
|
+
author_blacklist=None,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
if metadata_doc is None:
|
|
215
|
+
return f"Error: Could not extract metadata from URL: {url}"
|
|
216
|
+
|
|
217
|
+
metadata_dict = metadata_doc.as_dict()
|
|
218
|
+
|
|
219
|
+
# Reset caches
|
|
220
|
+
reset_caches()
|
|
221
|
+
|
|
222
|
+
if as_json:
|
|
223
|
+
return json.dumps(metadata_dict, indent=2, default=str)
|
|
224
|
+
else:
|
|
225
|
+
return "\n".join(f"{key}: {value}" for key, value in metadata_dict.items())
|
|
226
|
+
|
|
227
|
+
except Exception as e:
|
|
228
|
+
logger.warning(f"Error extracting metadata from {url}: {e}")
|
|
229
|
+
return f"Error extracting metadata from {url}: {e}"
|
|
230
|
+
|
|
231
|
+
def crawl_website(
|
|
232
|
+
self,
|
|
233
|
+
homepage_url: str,
|
|
234
|
+
extract_content: bool = False,
|
|
235
|
+
) -> str:
|
|
236
|
+
"""
|
|
237
|
+
Crawl a website and optionally extract content from discovered pages.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
homepage_url (str): The starting URL (preferably homepage) to crawl from.
|
|
241
|
+
extract_content (bool): Whether to extract content from discovered URLs.
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
str: JSON containing crawl results and optionally extracted content.
|
|
245
|
+
"""
|
|
246
|
+
if not SPIDER_AVAILABLE:
|
|
247
|
+
return "Error: Web crawling functionality not available. Trafilatura spider module could not be imported."
|
|
248
|
+
|
|
249
|
+
try:
|
|
250
|
+
log_debug(f"Starting website crawl from: {homepage_url}")
|
|
251
|
+
|
|
252
|
+
# Use instance configuration
|
|
253
|
+
max_seen = self.max_crawl_urls
|
|
254
|
+
max_known = self.max_known_urls
|
|
255
|
+
lang = self.target_language
|
|
256
|
+
|
|
257
|
+
# Perform focused crawling
|
|
258
|
+
to_visit, known_links = focused_crawler(
|
|
259
|
+
homepage=homepage_url,
|
|
260
|
+
max_seen_urls=max_seen,
|
|
261
|
+
max_known_urls=max_known,
|
|
262
|
+
lang=lang,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
crawl_results = {
|
|
266
|
+
"homepage": homepage_url,
|
|
267
|
+
"to_visit": list(to_visit) if to_visit else [],
|
|
268
|
+
"known_links": list(known_links) if known_links else [],
|
|
269
|
+
"stats": {
|
|
270
|
+
"urls_to_visit": len(to_visit) if to_visit else 0,
|
|
271
|
+
"known_links_count": len(known_links) if known_links else 0,
|
|
272
|
+
},
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
# Optionally extract content from discovered URLs
|
|
276
|
+
if extract_content and known_links:
|
|
277
|
+
log_debug("Extracting content from discovered URLs")
|
|
278
|
+
extracted_content = {}
|
|
279
|
+
|
|
280
|
+
# Limit extraction to avoid overwhelming responses
|
|
281
|
+
urls_to_extract = list(known_links)[: min(10, len(known_links))]
|
|
282
|
+
|
|
283
|
+
for url in urls_to_extract:
|
|
284
|
+
try:
|
|
285
|
+
params = self._get_extraction_params()
|
|
286
|
+
|
|
287
|
+
html_content = fetch_url(url)
|
|
288
|
+
if html_content:
|
|
289
|
+
content = extract(html_content, url=url, **params)
|
|
290
|
+
if content:
|
|
291
|
+
extracted_content[url] = content
|
|
292
|
+
except Exception as e:
|
|
293
|
+
extracted_content[url] = f"Error extracting content: {e}"
|
|
294
|
+
|
|
295
|
+
crawl_results["extracted_content"] = extracted_content
|
|
296
|
+
|
|
297
|
+
# Reset caches
|
|
298
|
+
reset_caches()
|
|
299
|
+
|
|
300
|
+
return json.dumps(crawl_results, indent=2, default=str)
|
|
301
|
+
|
|
302
|
+
except Exception as e:
|
|
303
|
+
logger.warning(f"Error crawling website {homepage_url}: {e}")
|
|
304
|
+
return f"Error crawling website {homepage_url}: {e}"
|
|
305
|
+
|
|
306
|
+
def html_to_text(
|
|
307
|
+
self,
|
|
308
|
+
html_content: str,
|
|
309
|
+
clean: bool = True,
|
|
310
|
+
) -> str:
|
|
311
|
+
"""
|
|
312
|
+
Convert HTML content to plain text using Trafilatura's html2txt function.
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
html_content (str): The HTML content to convert.
|
|
316
|
+
clean (bool): Whether to remove potentially undesirable elements.
|
|
317
|
+
|
|
318
|
+
Returns:
|
|
319
|
+
str: Plain text extracted from HTML.
|
|
320
|
+
"""
|
|
321
|
+
try:
|
|
322
|
+
log_debug("Converting HTML to text")
|
|
323
|
+
|
|
324
|
+
result = html2txt(html_content, clean=clean)
|
|
325
|
+
|
|
326
|
+
# Reset caches
|
|
327
|
+
reset_caches()
|
|
328
|
+
|
|
329
|
+
return result if result else "Error: Could not extract text from HTML content"
|
|
330
|
+
|
|
331
|
+
except Exception as e:
|
|
332
|
+
logger.warning(f"Error converting HTML to text: {e}")
|
|
333
|
+
return f"Error converting HTML to text: {e}"
|
|
334
|
+
|
|
335
|
+
def extract_batch(
|
|
336
|
+
self,
|
|
337
|
+
urls: List[str],
|
|
338
|
+
) -> str:
|
|
339
|
+
"""
|
|
340
|
+
Extract content from multiple URLs in batch.
|
|
341
|
+
|
|
342
|
+
Args:
|
|
343
|
+
urls (List[str]): List of URLs to extract content from.
|
|
344
|
+
|
|
345
|
+
Returns:
|
|
346
|
+
str: JSON containing batch extraction results.
|
|
347
|
+
"""
|
|
348
|
+
try:
|
|
349
|
+
log_debug(f"Starting batch extraction for {len(urls)} URLs")
|
|
350
|
+
|
|
351
|
+
results = {}
|
|
352
|
+
failed_urls = []
|
|
353
|
+
|
|
354
|
+
for url in urls:
|
|
355
|
+
try:
|
|
356
|
+
params = self._get_extraction_params()
|
|
357
|
+
|
|
358
|
+
html_content = fetch_url(url)
|
|
359
|
+
if html_content:
|
|
360
|
+
content = extract(html_content, url=url, **params)
|
|
361
|
+
if content:
|
|
362
|
+
results[url] = content
|
|
363
|
+
else:
|
|
364
|
+
failed_urls.append(url)
|
|
365
|
+
else:
|
|
366
|
+
failed_urls.append(url)
|
|
367
|
+
|
|
368
|
+
except Exception as e:
|
|
369
|
+
failed_urls.append(url)
|
|
370
|
+
results[url] = f"Error: {e}"
|
|
371
|
+
|
|
372
|
+
# Reset caches after batch processing
|
|
373
|
+
reset_caches()
|
|
374
|
+
|
|
375
|
+
batch_results = {
|
|
376
|
+
"successful_extractions": len(results)
|
|
377
|
+
- len([k for k, v in results.items() if str(v).startswith("Error:")]),
|
|
378
|
+
"failed_extractions": len(failed_urls),
|
|
379
|
+
"total_urls": len(urls),
|
|
380
|
+
"results": results,
|
|
381
|
+
"failed_urls": failed_urls,
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return json.dumps(batch_results, indent=2, default=str)
|
|
385
|
+
|
|
386
|
+
except Exception as e:
|
|
387
|
+
logger.warning(f"Error in batch extraction: {e}")
|
|
388
|
+
return f"Error in batch extraction: {e}"
|
agno/tools/trello.py
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from os import getenv
|
|
3
|
+
from typing import Any, List, Optional
|
|
4
|
+
|
|
5
|
+
from agno.tools import Toolkit
|
|
6
|
+
from agno.utils.log import log_debug, log_info, logger
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from trello import TrelloClient # type: ignore
|
|
10
|
+
except ImportError:
|
|
11
|
+
raise ImportError("`py-trello` not installed.")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TrelloTools(Toolkit):
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
api_key: Optional[str] = None,
|
|
18
|
+
api_secret: Optional[str] = None,
|
|
19
|
+
token: Optional[str] = None,
|
|
20
|
+
**kwargs,
|
|
21
|
+
):
|
|
22
|
+
self.api_key = api_key or getenv("TRELLO_API_KEY")
|
|
23
|
+
self.api_secret = api_secret or getenv("TRELLO_API_SECRET")
|
|
24
|
+
self.token = token or getenv("TRELLO_TOKEN")
|
|
25
|
+
|
|
26
|
+
if not all([self.api_key, self.api_secret, self.token]):
|
|
27
|
+
logger.warning("Missing Trello credentials")
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
self.client = TrelloClient(api_key=self.api_key, api_secret=self.api_secret, token=self.token)
|
|
31
|
+
except Exception as e:
|
|
32
|
+
logger.error(f"Error initializing Trello client: {e}")
|
|
33
|
+
self.client = None
|
|
34
|
+
|
|
35
|
+
tools: List[Any] = [
|
|
36
|
+
self.create_card,
|
|
37
|
+
self.get_board_lists,
|
|
38
|
+
self.move_card,
|
|
39
|
+
self.get_cards,
|
|
40
|
+
self.create_board,
|
|
41
|
+
self.create_list,
|
|
42
|
+
self.list_boards,
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
super().__init__(name="trello", tools=tools, **kwargs)
|
|
46
|
+
|
|
47
|
+
def create_card(self, board_id: str, list_name: str, card_title: str, description: str = "") -> str:
|
|
48
|
+
"""
|
|
49
|
+
Create a new card in the specified board and list.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
board_id (str): ID of the board to create the card in
|
|
53
|
+
list_name (str): Name of the list to add the card to
|
|
54
|
+
card_title (str): Title of the card
|
|
55
|
+
description (str): Description of the card
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
str: JSON string containing card details or error message
|
|
59
|
+
"""
|
|
60
|
+
try:
|
|
61
|
+
if not self.client:
|
|
62
|
+
return "Trello client not initialized"
|
|
63
|
+
|
|
64
|
+
log_info(f"Creating card {card_title}")
|
|
65
|
+
|
|
66
|
+
board = self.client.get_board(board_id)
|
|
67
|
+
target_list = None
|
|
68
|
+
|
|
69
|
+
for lst in board.list_lists():
|
|
70
|
+
if lst.name.lower() == list_name.lower():
|
|
71
|
+
target_list = lst
|
|
72
|
+
break
|
|
73
|
+
|
|
74
|
+
if not target_list:
|
|
75
|
+
return f"List '{list_name}' not found on board"
|
|
76
|
+
|
|
77
|
+
card = target_list.add_card(name=card_title, desc=description)
|
|
78
|
+
|
|
79
|
+
return json.dumps({"id": card.id, "name": card.name, "url": card.url, "list": list_name})
|
|
80
|
+
|
|
81
|
+
except Exception as e:
|
|
82
|
+
return f"Error creating card: {e}"
|
|
83
|
+
|
|
84
|
+
def get_board_lists(self, board_id: str) -> str:
|
|
85
|
+
"""
|
|
86
|
+
Get all lists on a board.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
board_id (str): ID of the board
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
str: JSON string containing lists information
|
|
93
|
+
"""
|
|
94
|
+
try:
|
|
95
|
+
if not self.client:
|
|
96
|
+
return "Trello client not initialized"
|
|
97
|
+
|
|
98
|
+
log_debug(f"Getting lists for board {board_id}")
|
|
99
|
+
|
|
100
|
+
board = self.client.get_board(board_id)
|
|
101
|
+
lists = board.list_lists()
|
|
102
|
+
|
|
103
|
+
lists_info = [{"id": lst.id, "name": lst.name, "cards_count": len(lst.list_cards())} for lst in lists]
|
|
104
|
+
|
|
105
|
+
return json.dumps({"lists": lists_info})
|
|
106
|
+
|
|
107
|
+
except Exception as e:
|
|
108
|
+
return f"Error getting board lists: {e}"
|
|
109
|
+
|
|
110
|
+
def move_card(self, card_id: str, list_id: str) -> str:
|
|
111
|
+
"""
|
|
112
|
+
Move a card to a different list.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
card_id (str): ID of the card to move
|
|
116
|
+
list_id (str): ID of the destination list
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
str: JSON string containing result of the operation
|
|
120
|
+
"""
|
|
121
|
+
try:
|
|
122
|
+
if not self.client:
|
|
123
|
+
return "Trello client not initialized"
|
|
124
|
+
|
|
125
|
+
log_debug(f"Moving card {card_id} to list {list_id}")
|
|
126
|
+
|
|
127
|
+
card = self.client.get_card(card_id)
|
|
128
|
+
card.change_list(list_id)
|
|
129
|
+
|
|
130
|
+
return json.dumps({"success": True, "card_id": card_id, "new_list_id": list_id})
|
|
131
|
+
|
|
132
|
+
except Exception as e:
|
|
133
|
+
return f"Error moving card: {e}"
|
|
134
|
+
|
|
135
|
+
def get_cards(self, list_id: str) -> str:
|
|
136
|
+
"""
|
|
137
|
+
Get all cards in a list.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
list_id (str): ID of the list
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
str: JSON string containing cards information
|
|
144
|
+
"""
|
|
145
|
+
try:
|
|
146
|
+
if not self.client:
|
|
147
|
+
return "Trello client not initialized"
|
|
148
|
+
|
|
149
|
+
log_debug(f"Getting cards for list {list_id}")
|
|
150
|
+
|
|
151
|
+
trello_list = self.client.get_list(list_id)
|
|
152
|
+
cards = trello_list.list_cards()
|
|
153
|
+
|
|
154
|
+
cards_info = [
|
|
155
|
+
{
|
|
156
|
+
"id": card.id,
|
|
157
|
+
"name": card.name,
|
|
158
|
+
"description": card.description,
|
|
159
|
+
"url": card.url,
|
|
160
|
+
"labels": [label.name for label in card.labels],
|
|
161
|
+
}
|
|
162
|
+
for card in cards
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
return json.dumps({"cards": cards_info})
|
|
166
|
+
|
|
167
|
+
except Exception as e:
|
|
168
|
+
return f"Error getting cards: {e}"
|
|
169
|
+
|
|
170
|
+
def create_board(self, name: str, default_lists: bool = False) -> str:
|
|
171
|
+
"""
|
|
172
|
+
Create a new Trello board.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
name (str): Name of the board
|
|
176
|
+
default_lists (bool): Whether the default lists should be created
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
str: JSON string containing board details or error message
|
|
180
|
+
"""
|
|
181
|
+
try:
|
|
182
|
+
if not self.client:
|
|
183
|
+
return "Trello client not initialized"
|
|
184
|
+
|
|
185
|
+
log_info(f"Creating board {name}")
|
|
186
|
+
|
|
187
|
+
board = self.client.add_board(board_name=name, default_lists=default_lists)
|
|
188
|
+
|
|
189
|
+
return json.dumps(
|
|
190
|
+
{
|
|
191
|
+
"id": board.id,
|
|
192
|
+
"name": board.name,
|
|
193
|
+
"url": board.url,
|
|
194
|
+
}
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
except Exception as e:
|
|
198
|
+
return f"Error creating board: {e}"
|
|
199
|
+
|
|
200
|
+
def create_list(self, board_id: str, list_name: str, pos: str = "bottom") -> str:
|
|
201
|
+
"""
|
|
202
|
+
Create a new list on a specified board.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
board_id (str): ID of the board to create the list in
|
|
206
|
+
list_name (str): Name of the new list
|
|
207
|
+
pos (str): Position of the list - 'top', 'bottom', or a positive number
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
str: JSON string containing list details or error message
|
|
211
|
+
"""
|
|
212
|
+
try:
|
|
213
|
+
if not self.client:
|
|
214
|
+
return "Trello client not initialized"
|
|
215
|
+
|
|
216
|
+
log_info(f"Creating list {list_name}")
|
|
217
|
+
|
|
218
|
+
board = self.client.get_board(board_id)
|
|
219
|
+
new_list = board.add_list(name=list_name, pos=pos)
|
|
220
|
+
|
|
221
|
+
return json.dumps(
|
|
222
|
+
{
|
|
223
|
+
"id": new_list.id,
|
|
224
|
+
"name": new_list.name,
|
|
225
|
+
"pos": new_list.pos,
|
|
226
|
+
"board_id": board_id,
|
|
227
|
+
}
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
except Exception as e:
|
|
231
|
+
return f"Error creating list: {e}"
|
|
232
|
+
|
|
233
|
+
def list_boards(self, board_filter: str = "all") -> str:
|
|
234
|
+
"""
|
|
235
|
+
Get a list of all boards for the authenticated user.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
board_filter (str): Filter for boards. Options: 'all', 'open', 'closed',
|
|
239
|
+
'organization', 'public', 'starred'. Defaults to 'all'.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
str: JSON string containing list of boards
|
|
243
|
+
"""
|
|
244
|
+
try:
|
|
245
|
+
if not self.client:
|
|
246
|
+
return "Trello client not initialized"
|
|
247
|
+
|
|
248
|
+
log_debug(f"Listing boards with filter: {board_filter}")
|
|
249
|
+
|
|
250
|
+
boards = self.client.list_boards(board_filter=board_filter)
|
|
251
|
+
|
|
252
|
+
boards_list = []
|
|
253
|
+
for board in boards:
|
|
254
|
+
board_data = {
|
|
255
|
+
"id": board.id,
|
|
256
|
+
"name": board.name,
|
|
257
|
+
"description": getattr(board, "description", ""),
|
|
258
|
+
"url": board.url,
|
|
259
|
+
"closed": board.closed,
|
|
260
|
+
"starred": getattr(board, "starred", False),
|
|
261
|
+
"organization": getattr(board, "idOrganization", None),
|
|
262
|
+
}
|
|
263
|
+
boards_list.append(board_data)
|
|
264
|
+
|
|
265
|
+
return json.dumps(
|
|
266
|
+
{
|
|
267
|
+
"filter_used": board_filter,
|
|
268
|
+
"total_boards": len(boards_list),
|
|
269
|
+
"boards": boards_list,
|
|
270
|
+
}
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
except Exception as e:
|
|
274
|
+
return f"Error listing boards: {e}"
|