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
agno/tools/__init__.py
ADDED
agno/tools/agentql.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
from os import getenv
|
|
2
|
+
from typing import Any, List, Optional
|
|
3
|
+
|
|
4
|
+
from agno.tools import Toolkit
|
|
5
|
+
from agno.utils.log import log_info
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
import agentql
|
|
9
|
+
from playwright.sync_api import sync_playwright
|
|
10
|
+
except ImportError:
|
|
11
|
+
raise ImportError("`agentql` not installed. Please install using `pip install agentql`")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AgentQLTools(Toolkit):
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
api_key: Optional[str] = None,
|
|
18
|
+
enable_scrape_website: bool = True,
|
|
19
|
+
enable_custom_scrape_website: bool = False,
|
|
20
|
+
all: bool = False,
|
|
21
|
+
agentql_query: str = "",
|
|
22
|
+
**kwargs,
|
|
23
|
+
):
|
|
24
|
+
self.api_key = api_key or getenv("AGENTQL_API_KEY")
|
|
25
|
+
if not self.api_key:
|
|
26
|
+
raise ValueError("AGENTQL_API_KEY not set. Please set the AGENTQL_API_KEY environment variable.")
|
|
27
|
+
|
|
28
|
+
self.agentql_query = agentql_query
|
|
29
|
+
|
|
30
|
+
tools: List[Any] = []
|
|
31
|
+
if all or enable_scrape_website:
|
|
32
|
+
tools.append(self.scrape_website)
|
|
33
|
+
if all or enable_custom_scrape_website or (agentql_query and not all and not enable_custom_scrape_website):
|
|
34
|
+
if agentql_query:
|
|
35
|
+
log_info("Custom AgentQL query provided. Registering custom scrape function.")
|
|
36
|
+
tools.append(self.custom_scrape_website)
|
|
37
|
+
|
|
38
|
+
super().__init__(name="agentql_tools", tools=tools, **kwargs)
|
|
39
|
+
|
|
40
|
+
def scrape_website(self, url: str) -> str:
|
|
41
|
+
"""
|
|
42
|
+
Scrape all text content from a website using AgentQL.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
url (str): The URL of the website to scrape
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
str: Extracted text content or error message
|
|
49
|
+
"""
|
|
50
|
+
if not url:
|
|
51
|
+
return "No URL provided"
|
|
52
|
+
|
|
53
|
+
TEXT_SEARCH_QUERY = """
|
|
54
|
+
{
|
|
55
|
+
text_content[]
|
|
56
|
+
}
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
with sync_playwright() as playwright, playwright.chromium.launch(headless=False) as browser:
|
|
61
|
+
page = agentql.wrap(browser.new_page())
|
|
62
|
+
page.goto(url)
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
# Get response from AgentQL query
|
|
66
|
+
response = page.query_data(TEXT_SEARCH_QUERY)
|
|
67
|
+
|
|
68
|
+
# Extract text based on response format
|
|
69
|
+
if isinstance(response, dict) and "text_content" in response:
|
|
70
|
+
text_items = [item for item in response["text_content"] if item and item.strip()]
|
|
71
|
+
|
|
72
|
+
deduplicated = list(set(text_items))
|
|
73
|
+
return " ".join(deduplicated)
|
|
74
|
+
|
|
75
|
+
except Exception as e:
|
|
76
|
+
return f"Error extracting text: {e}"
|
|
77
|
+
except Exception as e:
|
|
78
|
+
return f"Error launching browser: {e}"
|
|
79
|
+
|
|
80
|
+
return "No text content found"
|
|
81
|
+
|
|
82
|
+
def custom_scrape_website(self, url: str) -> str:
|
|
83
|
+
"""
|
|
84
|
+
Scrape a website using a custom AgentQL query.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
url (str): The URL of the website to scrape
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
str: Extracted text content or error message
|
|
91
|
+
"""
|
|
92
|
+
if not url:
|
|
93
|
+
return "No URL provided"
|
|
94
|
+
|
|
95
|
+
if self.agentql_query == "":
|
|
96
|
+
return "Custom AgentQL query not provided. Please provide a custom AgentQL query."
|
|
97
|
+
|
|
98
|
+
try:
|
|
99
|
+
with sync_playwright() as playwright, playwright.chromium.launch(headless=False) as browser:
|
|
100
|
+
page = agentql.wrap(browser.new_page())
|
|
101
|
+
page.goto(url)
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
# Get response from AgentQL query
|
|
105
|
+
response = page.query_data(self.agentql_query)
|
|
106
|
+
|
|
107
|
+
# Extract text based on response format
|
|
108
|
+
if isinstance(response, dict):
|
|
109
|
+
items = [item for item in response]
|
|
110
|
+
text_items = [text_item for text_item in items if text_item]
|
|
111
|
+
|
|
112
|
+
deduplicated = list(set(text_items))
|
|
113
|
+
return " ".join(deduplicated)
|
|
114
|
+
|
|
115
|
+
except Exception as e:
|
|
116
|
+
return f"Error extracting text: {e}"
|
|
117
|
+
except Exception as e:
|
|
118
|
+
return f"Error launching browser: {e}"
|
|
119
|
+
|
|
120
|
+
return "No text content found"
|
agno/tools/airflow.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Any, List, Optional, Union
|
|
3
|
+
|
|
4
|
+
from agno.tools import Toolkit
|
|
5
|
+
from agno.utils.log import log_debug, log_info, logger
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AirflowTools(Toolkit):
|
|
9
|
+
def __init__(
|
|
10
|
+
self,
|
|
11
|
+
dags_dir: Optional[Union[Path, str]] = None,
|
|
12
|
+
enable_save_dag_file: bool = True,
|
|
13
|
+
enable_read_dag_file: bool = True,
|
|
14
|
+
all: bool = False,
|
|
15
|
+
**kwargs,
|
|
16
|
+
):
|
|
17
|
+
"""
|
|
18
|
+
quick start to work with airflow : https://airflow.apache.org/docs/apache-airflow/stable/start.html
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
_dags_dir: Optional[Path] = None
|
|
22
|
+
if dags_dir is not None:
|
|
23
|
+
if isinstance(dags_dir, str):
|
|
24
|
+
_dags_dir = Path.cwd().joinpath(dags_dir)
|
|
25
|
+
else:
|
|
26
|
+
_dags_dir = dags_dir
|
|
27
|
+
self.dags_dir: Path = _dags_dir or Path.cwd()
|
|
28
|
+
|
|
29
|
+
tools: List[Any] = []
|
|
30
|
+
if all or enable_save_dag_file:
|
|
31
|
+
tools.append(self.save_dag_file)
|
|
32
|
+
if all or enable_read_dag_file:
|
|
33
|
+
tools.append(self.read_dag_file)
|
|
34
|
+
|
|
35
|
+
super().__init__(name="AirflowTools", tools=tools, **kwargs)
|
|
36
|
+
|
|
37
|
+
def save_dag_file(self, contents: str, dag_file: str) -> str:
|
|
38
|
+
"""Saves python code for an Airflow DAG to a file called `dag_file` and returns the file path if successful.
|
|
39
|
+
|
|
40
|
+
:param contents: The contents of the DAG.
|
|
41
|
+
:param dag_file: The name of the file to save to.
|
|
42
|
+
:return: The file path if successful, otherwise returns an error message.
|
|
43
|
+
"""
|
|
44
|
+
try:
|
|
45
|
+
file_path = self.dags_dir.joinpath(dag_file)
|
|
46
|
+
log_debug(f"Saving contents to {file_path}")
|
|
47
|
+
if not file_path.parent.exists():
|
|
48
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
49
|
+
file_path.write_text(contents)
|
|
50
|
+
log_info(f"Saved: {file_path}")
|
|
51
|
+
return str(file_path)
|
|
52
|
+
except Exception as e:
|
|
53
|
+
logger.error(f"Error saving to file: {e}")
|
|
54
|
+
return f"Error saving to file: {e}"
|
|
55
|
+
|
|
56
|
+
def read_dag_file(self, dag_file: str) -> str:
|
|
57
|
+
"""Reads an Airflow DAG file `dag_file` and returns the contents if successful.
|
|
58
|
+
|
|
59
|
+
:param dag_file: The name of the file to read
|
|
60
|
+
:return: The contents of the file if successful, otherwise returns an error message.
|
|
61
|
+
"""
|
|
62
|
+
try:
|
|
63
|
+
log_info(f"Reading file: {dag_file}")
|
|
64
|
+
file_path = self.dags_dir.joinpath(dag_file)
|
|
65
|
+
contents = file_path.read_text()
|
|
66
|
+
return str(contents)
|
|
67
|
+
except Exception as e:
|
|
68
|
+
logger.error(f"Error reading file: {e}")
|
|
69
|
+
return f"Error reading file: {e}"
|
agno/tools/api.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Any, Dict, List, Literal, Optional
|
|
3
|
+
|
|
4
|
+
from agno.tools import Toolkit
|
|
5
|
+
from agno.utils.log import log_debug, logger
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
import requests
|
|
9
|
+
from requests.auth import HTTPBasicAuth
|
|
10
|
+
except ImportError:
|
|
11
|
+
raise ImportError("`requests` not installed. Please install using `pip install requests`")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CustomApiTools(Toolkit):
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
base_url: Optional[str] = None,
|
|
18
|
+
username: Optional[str] = None,
|
|
19
|
+
password: Optional[str] = None,
|
|
20
|
+
api_key: Optional[str] = None,
|
|
21
|
+
headers: Optional[Dict[str, str]] = None,
|
|
22
|
+
verify_ssl: bool = True,
|
|
23
|
+
timeout: int = 30,
|
|
24
|
+
enable_make_request: bool = True,
|
|
25
|
+
all: bool = False,
|
|
26
|
+
**kwargs,
|
|
27
|
+
):
|
|
28
|
+
self.base_url = base_url
|
|
29
|
+
self.username = username
|
|
30
|
+
self.password = password
|
|
31
|
+
self.api_key = api_key
|
|
32
|
+
self.default_headers = headers or {}
|
|
33
|
+
self.verify_ssl = verify_ssl
|
|
34
|
+
self.timeout = timeout
|
|
35
|
+
|
|
36
|
+
tools: List[Any] = []
|
|
37
|
+
if all or enable_make_request:
|
|
38
|
+
tools.append(self.make_request)
|
|
39
|
+
|
|
40
|
+
super().__init__(name="api_tools", tools=tools, **kwargs)
|
|
41
|
+
|
|
42
|
+
def _get_auth(self) -> Optional[HTTPBasicAuth]:
|
|
43
|
+
"""Get authentication object if credentials are provided."""
|
|
44
|
+
if self.username and self.password:
|
|
45
|
+
return HTTPBasicAuth(self.username, self.password)
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
def _get_headers(self, additional_headers: Optional[Dict[str, str]] = None) -> Dict[str, str]:
|
|
49
|
+
"""Combine default headers with additional headers."""
|
|
50
|
+
headers = self.default_headers.copy()
|
|
51
|
+
if self.api_key:
|
|
52
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
53
|
+
if additional_headers:
|
|
54
|
+
headers.update(additional_headers)
|
|
55
|
+
return headers
|
|
56
|
+
|
|
57
|
+
def make_request(
|
|
58
|
+
self,
|
|
59
|
+
endpoint: str,
|
|
60
|
+
method: Literal["GET", "POST", "PUT", "DELETE", "PATCH"] = "GET",
|
|
61
|
+
params: Optional[Dict[str, Any]] = None,
|
|
62
|
+
data: Optional[Dict[str, Any]] = None,
|
|
63
|
+
headers: Optional[Dict[str, str]] = None,
|
|
64
|
+
json_data: Optional[Dict[str, Any]] = None,
|
|
65
|
+
) -> str:
|
|
66
|
+
"""Make an HTTP request to the API.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
method (str): HTTP method (GET, POST, PUT, DELETE, PATCH)
|
|
70
|
+
endpoint (str): API endpoint (will be combined with base_url if set)
|
|
71
|
+
params (Optional[Dict[str, Any]]): Query parameters
|
|
72
|
+
data (Optional[Dict[str, Any]]): Form data to send
|
|
73
|
+
headers (Optional[Dict[str, str]]): Additional headers
|
|
74
|
+
json_data (Optional[Dict[str, Any]]): JSON data to send
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
str: JSON string containing response data or error message
|
|
78
|
+
"""
|
|
79
|
+
try:
|
|
80
|
+
if self.base_url:
|
|
81
|
+
url = f"{self.base_url.rstrip('/')}/{endpoint.lstrip('/')}"
|
|
82
|
+
else:
|
|
83
|
+
url = endpoint
|
|
84
|
+
log_debug(f"Making {method} request to {url}")
|
|
85
|
+
|
|
86
|
+
response = requests.request(
|
|
87
|
+
method=method,
|
|
88
|
+
url=url,
|
|
89
|
+
params=params,
|
|
90
|
+
data=data,
|
|
91
|
+
json=json_data,
|
|
92
|
+
headers=self._get_headers(headers),
|
|
93
|
+
auth=self._get_auth(),
|
|
94
|
+
verify=self.verify_ssl,
|
|
95
|
+
timeout=self.timeout,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
try:
|
|
99
|
+
response_data = response.json()
|
|
100
|
+
except json.JSONDecodeError:
|
|
101
|
+
response_data = {"text": response.text}
|
|
102
|
+
|
|
103
|
+
result = {
|
|
104
|
+
"status_code": response.status_code,
|
|
105
|
+
"headers": dict(response.headers),
|
|
106
|
+
"data": response_data,
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if not response.ok:
|
|
110
|
+
logger.error(f"Request failed with status {response.status_code}: {response.text}")
|
|
111
|
+
result["error"] = "Request failed"
|
|
112
|
+
|
|
113
|
+
return json.dumps(result, indent=2)
|
|
114
|
+
|
|
115
|
+
except requests.exceptions.RequestException as e:
|
|
116
|
+
error_message = f"Request failed: {str(e)}"
|
|
117
|
+
logger.error(error_message)
|
|
118
|
+
return json.dumps({"error": error_message}, indent=2)
|
|
119
|
+
except Exception as e:
|
|
120
|
+
error_message = f"Unexpected error: {str(e)}"
|
|
121
|
+
logger.error(error_message)
|
|
122
|
+
return json.dumps({"error": error_message}, indent=2)
|
agno/tools/apify.py
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import string
|
|
3
|
+
from os import getenv
|
|
4
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
from agno.tools import Toolkit
|
|
9
|
+
from agno.utils.log import log_info, logger
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from apify_client import ApifyClient
|
|
13
|
+
except ImportError:
|
|
14
|
+
raise ImportError("`apify-client` not installed. Please install using `pip install apify-client`")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ApifyTools(Toolkit):
|
|
18
|
+
def __init__(self, actors: Optional[Union[str, List[str]]] = None, apify_api_token: Optional[str] = None):
|
|
19
|
+
"""Initialize ApifyTools with specific Actors.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
actors (Optional[Union[str, List[str]]]): Single Actor ID as string or list of Actor IDs to register as individual tools
|
|
23
|
+
apify_api_token (Optional[str]): Apify API token (defaults to APIFY_API_TOKEN env variable)
|
|
24
|
+
"""
|
|
25
|
+
# Get API token from args or environment
|
|
26
|
+
self.apify_api_token = apify_api_token or getenv("APIFY_API_TOKEN")
|
|
27
|
+
if not self.apify_api_token:
|
|
28
|
+
raise ValueError("APIFY_API_TOKEN environment variable or apify_api_token parameter must be set")
|
|
29
|
+
|
|
30
|
+
self.client = create_apify_client(self.apify_api_token)
|
|
31
|
+
|
|
32
|
+
tools: List[Any] = []
|
|
33
|
+
if actors:
|
|
34
|
+
actor_list = [actors] if isinstance(actors, str) else actors
|
|
35
|
+
for actor_id in actor_list:
|
|
36
|
+
tools.append(actor_id)
|
|
37
|
+
|
|
38
|
+
super().__init__(name="ApifyTools", tools=[], auto_register=False)
|
|
39
|
+
|
|
40
|
+
for actor_id in tools:
|
|
41
|
+
self.register_actor(actor_id)
|
|
42
|
+
|
|
43
|
+
def register_actor(self, actor_id: str) -> None:
|
|
44
|
+
"""Register an Apify Actor as a function in the toolkit.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
actor_id (str): ID of the Apify Actor to register (e.g., 'apify/web-scraper')
|
|
48
|
+
"""
|
|
49
|
+
try:
|
|
50
|
+
# Get actor metadata
|
|
51
|
+
build = get_actor_latest_build(self.client, actor_id)
|
|
52
|
+
tool_name = actor_id_to_tool_name(actor_id)
|
|
53
|
+
|
|
54
|
+
# Get actor description
|
|
55
|
+
actor_description = build.get("actorDefinition", {}).get("description", "")
|
|
56
|
+
if len(actor_description) > MAX_DESCRIPTION_LEN:
|
|
57
|
+
actor_description = actor_description[:MAX_DESCRIPTION_LEN] + "...(TRUNCATED, TOO LONG)"
|
|
58
|
+
|
|
59
|
+
# Get input schema
|
|
60
|
+
actor_input = build.get("actorDefinition", {}).get("input")
|
|
61
|
+
if not actor_input:
|
|
62
|
+
raise ValueError(f"Input schema not found in the Actor build for Actor: {actor_id}")
|
|
63
|
+
|
|
64
|
+
properties, required = prune_actor_input_schema(actor_input)
|
|
65
|
+
|
|
66
|
+
# Create a wrapper function that calls the Actor
|
|
67
|
+
def actor_function(**kwargs) -> str:
|
|
68
|
+
"""Actor function wrapper."""
|
|
69
|
+
try:
|
|
70
|
+
# Params are nested under 'kwargs' key
|
|
71
|
+
if len(kwargs) == 1 and "kwargs" in kwargs:
|
|
72
|
+
kwargs = kwargs["kwargs"]
|
|
73
|
+
|
|
74
|
+
log_info(f"Running Apify Actor {actor_id} with parameters: {kwargs}")
|
|
75
|
+
|
|
76
|
+
# Run the Actor directly with the client
|
|
77
|
+
details = self.client.actor(actor_id=actor_id).call(run_input=kwargs)
|
|
78
|
+
if details is None:
|
|
79
|
+
error_msg = (
|
|
80
|
+
f"Actor: {actor_id} was not started properly and details about the run were not returned"
|
|
81
|
+
)
|
|
82
|
+
raise ValueError(error_msg)
|
|
83
|
+
|
|
84
|
+
run_id = details.get("id")
|
|
85
|
+
if run_id is None:
|
|
86
|
+
error_msg = f"Run ID not found in the run details for Actor: {actor_id}"
|
|
87
|
+
raise ValueError(error_msg)
|
|
88
|
+
|
|
89
|
+
# Get the results
|
|
90
|
+
run = self.client.run(run_id=run_id)
|
|
91
|
+
results = run.dataset().list_items(clean=True).items
|
|
92
|
+
|
|
93
|
+
return json.dumps(results)
|
|
94
|
+
|
|
95
|
+
except Exception as e:
|
|
96
|
+
error_msg = f"Error running Apify Actor {actor_id}: {str(e)}"
|
|
97
|
+
logger.error(error_msg)
|
|
98
|
+
return json.dumps([{"error": error_msg}])
|
|
99
|
+
|
|
100
|
+
docstring = f"{actor_description}\n\nArgs:\n"
|
|
101
|
+
|
|
102
|
+
for param_name, param_info in properties.items():
|
|
103
|
+
param_type = param_info.get("type", "any")
|
|
104
|
+
param_desc = param_info.get("description", "No description available")
|
|
105
|
+
required_marker = "(required)" if param_name in required else "(optional)"
|
|
106
|
+
docstring += f" {param_name} ({param_type}): {required_marker} {param_desc}\n"
|
|
107
|
+
|
|
108
|
+
docstring += """
|
|
109
|
+
Returns:
|
|
110
|
+
str: JSON string containing the Actor's output dataset
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
# Update function metadata
|
|
114
|
+
actor_function.__name__ = tool_name
|
|
115
|
+
actor_function.__doc__ = docstring
|
|
116
|
+
|
|
117
|
+
# Register the function with the toolkit
|
|
118
|
+
self.register(actor_function)
|
|
119
|
+
# Fix params schema
|
|
120
|
+
self.functions[tool_name].parameters = props_to_json_schema(properties, required)
|
|
121
|
+
log_info(f"Registered Apify Actor '{actor_id}' as function '{tool_name}'")
|
|
122
|
+
|
|
123
|
+
except Exception as e:
|
|
124
|
+
logger.error(f"Failed to register Apify Actor '{actor_id}': {str(e)}")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
# Constants
|
|
128
|
+
MAX_DESCRIPTION_LEN = 350
|
|
129
|
+
REQUESTS_TIMEOUT_SECS = 300
|
|
130
|
+
APIFY_API_ENDPOINT_GET_DEFAULT_BUILD = "https://api.apify.com/v2/acts/{actor_id}/builds/default"
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# Utility functions
|
|
134
|
+
def props_to_json_schema(input_dict, required_fields=None):
|
|
135
|
+
schema: Dict[str, Any] = {"type": "object", "properties": {}, "required": required_fields or []}
|
|
136
|
+
|
|
137
|
+
def infer_array_item_type(prop):
|
|
138
|
+
type_map = {
|
|
139
|
+
"string": "string",
|
|
140
|
+
"int": "number",
|
|
141
|
+
"float": "number",
|
|
142
|
+
"dict": "object",
|
|
143
|
+
"list": "array",
|
|
144
|
+
"bool": "boolean",
|
|
145
|
+
"none": "null",
|
|
146
|
+
}
|
|
147
|
+
if prop.get("items", {}).get("type"):
|
|
148
|
+
return prop["items"]["type"]
|
|
149
|
+
if "prefill" in prop and prop["prefill"] and len(prop["prefill"]) > 0:
|
|
150
|
+
return type_map.get(type(prop["prefill"][0]).__name__.lower(), "string")
|
|
151
|
+
if "default" in prop and prop["default"] and len(prop["default"]) > 0:
|
|
152
|
+
return type_map.get(type(prop["default"][0]).__name__.lower(), "string")
|
|
153
|
+
return "string" # Fallback for arrays like searchStringsArray
|
|
154
|
+
|
|
155
|
+
for key, value in input_dict.items():
|
|
156
|
+
prop_schema: Dict[str, Any] = {}
|
|
157
|
+
prop_type = value.get("type")
|
|
158
|
+
|
|
159
|
+
if "enum" in value:
|
|
160
|
+
prop_schema["enum"] = value["enum"]
|
|
161
|
+
|
|
162
|
+
if "default" in value:
|
|
163
|
+
prop_schema["default"] = value["default"]
|
|
164
|
+
elif "prefill" in value:
|
|
165
|
+
prop_schema["default"] = value["prefill"]
|
|
166
|
+
|
|
167
|
+
if "description" in value:
|
|
168
|
+
prop_schema["description"] = value["description"]
|
|
169
|
+
|
|
170
|
+
# Handle Apify special types first
|
|
171
|
+
if prop_type == "object" and value.get("editor") == "proxy":
|
|
172
|
+
prop_schema["type"] = "object"
|
|
173
|
+
prop_schema["properties"] = {
|
|
174
|
+
"useApifyProxy": {
|
|
175
|
+
"title": "Use Apify Proxy",
|
|
176
|
+
"type": "boolean",
|
|
177
|
+
"description": "Whether to use Apify Proxy - ALWAYS SET TO TRUE.",
|
|
178
|
+
"default": True,
|
|
179
|
+
"examples": [True],
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
prop_schema["required"] = ["useApifyProxy"]
|
|
183
|
+
if "default" in value:
|
|
184
|
+
prop_schema["default"] = value["default"]
|
|
185
|
+
|
|
186
|
+
elif prop_type == "array" and value.get("editor") == "requestListSources":
|
|
187
|
+
prop_schema["type"] = "array"
|
|
188
|
+
prop_schema["items"] = {
|
|
189
|
+
"type": "object",
|
|
190
|
+
"title": "Request list source",
|
|
191
|
+
"description": "Request list source",
|
|
192
|
+
"properties": {
|
|
193
|
+
"url": {"title": "URL", "type": "string", "description": "URL of the request list source"}
|
|
194
|
+
},
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
elif prop_type == "array":
|
|
198
|
+
prop_schema["type"] = "array"
|
|
199
|
+
prop_schema["items"] = {
|
|
200
|
+
"type": infer_array_item_type(value),
|
|
201
|
+
"title": value.get("title", "Item"),
|
|
202
|
+
"description": "Item",
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
elif prop_type == "object":
|
|
206
|
+
prop_schema["type"] = "object"
|
|
207
|
+
if "default" in value:
|
|
208
|
+
prop_schema["default"] = value["default"]
|
|
209
|
+
prop_schema["properties"] = {}
|
|
210
|
+
for k, v in value.get("properties", value["default"]).items():
|
|
211
|
+
prop_type = v["type"] if isinstance(v, dict) else type(v).__name__.lower()
|
|
212
|
+
if prop_type == "bool":
|
|
213
|
+
prop_type = "boolean"
|
|
214
|
+
prop_schema["properties"][k] = {"type": prop_type}
|
|
215
|
+
|
|
216
|
+
else:
|
|
217
|
+
prop_schema["type"] = prop_type
|
|
218
|
+
|
|
219
|
+
schema["properties"][key] = prop_schema
|
|
220
|
+
|
|
221
|
+
return schema
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def create_apify_client(token: str) -> ApifyClient:
|
|
225
|
+
"""Create an Apify client instance with a custom user-agent.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
token (str): API token
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
ApifyClient: Apify client instance
|
|
232
|
+
|
|
233
|
+
Raises:
|
|
234
|
+
ValueError: If the API token is not provided
|
|
235
|
+
"""
|
|
236
|
+
if not token:
|
|
237
|
+
raise ValueError("API token is required to create an Apify client.")
|
|
238
|
+
|
|
239
|
+
client = ApifyClient(token)
|
|
240
|
+
if http_client := getattr(client.http_client, "httpx_client", None):
|
|
241
|
+
http_client.headers["user-agent"] += "; Origin/agno"
|
|
242
|
+
return client
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def actor_id_to_tool_name(actor_id: str) -> str:
|
|
246
|
+
"""Turn actor_id into a valid tool name.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
actor_id (str): Actor ID from Apify store
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
str: A valid tool name
|
|
253
|
+
"""
|
|
254
|
+
valid_chars = string.ascii_letters + string.digits + "_-"
|
|
255
|
+
return "apify_actor_" + "".join(char if char in valid_chars else "_" for char in actor_id)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def get_actor_latest_build(apify_client: ApifyClient, actor_id: str) -> Dict[str, Any]:
|
|
259
|
+
"""Get the latest build of an Actor from the default build tag.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
apify_client (ApifyClient): An instance of the ApifyClient class
|
|
263
|
+
actor_id (str): Actor name from Apify store to run
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
Dict[str, Any]: The latest build of the Actor
|
|
267
|
+
|
|
268
|
+
Raises:
|
|
269
|
+
ValueError: If the Actor is not found or the build data is not found
|
|
270
|
+
TypeError: If the build is not a dictionary
|
|
271
|
+
"""
|
|
272
|
+
if not (actor := apify_client.actor(actor_id).get()):
|
|
273
|
+
raise ValueError(f"Actor {actor_id} not found.")
|
|
274
|
+
|
|
275
|
+
if not (actor_obj_id := actor.get("id")):
|
|
276
|
+
raise ValueError(f"Failed to get the Actor object ID for {actor_id}.")
|
|
277
|
+
|
|
278
|
+
url = APIFY_API_ENDPOINT_GET_DEFAULT_BUILD.format(actor_id=actor_obj_id)
|
|
279
|
+
response = requests.request("GET", url, timeout=REQUESTS_TIMEOUT_SECS)
|
|
280
|
+
|
|
281
|
+
build = response.json()
|
|
282
|
+
if not isinstance(build, dict):
|
|
283
|
+
raise TypeError(f"Failed to get the latest build of the Actor {actor_id}.")
|
|
284
|
+
|
|
285
|
+
if (data := build.get("data")) is None:
|
|
286
|
+
raise ValueError(f"Failed to get the latest build data of the Actor {actor_id}.")
|
|
287
|
+
|
|
288
|
+
return data
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def prune_actor_input_schema(input_schema: Dict[str, Any]) -> Tuple[Dict[str, Any], List[str]]:
|
|
292
|
+
"""Get the input schema from the Actor build and trim descriptions.
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
input_schema (Dict[str, Any]): The input schema from the Actor build
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
Tuple[Dict[str, Any], List[str]]: A tuple containing the pruned properties and required fields
|
|
299
|
+
"""
|
|
300
|
+
properties = input_schema.get("properties", {})
|
|
301
|
+
required = input_schema.get("required", [])
|
|
302
|
+
|
|
303
|
+
properties_out: Dict[str, Any] = {}
|
|
304
|
+
for item, meta in properties.items():
|
|
305
|
+
properties_out[item] = {}
|
|
306
|
+
if desc := meta.get("description"):
|
|
307
|
+
properties_out[item]["description"] = (
|
|
308
|
+
desc[:MAX_DESCRIPTION_LEN] + "..." if len(desc) > MAX_DESCRIPTION_LEN else desc
|
|
309
|
+
)
|
|
310
|
+
for key_name in ("type", "default", "prefill", "enum"):
|
|
311
|
+
if value := meta.get(key_name):
|
|
312
|
+
properties_out[item][key_name] = value
|
|
313
|
+
|
|
314
|
+
return properties_out, required
|