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/brandfetch.py
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Going to contribute this to agno toolkits.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from os import getenv
|
|
6
|
+
from typing import Any, Optional
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
import httpx
|
|
10
|
+
except ImportError:
|
|
11
|
+
raise ImportError("`httpx` not installed.")
|
|
12
|
+
|
|
13
|
+
from agno.tools import Toolkit
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BrandfetchTools(Toolkit):
|
|
17
|
+
"""
|
|
18
|
+
Brandfetch API toolkit for retrieving brand data and searching brands.
|
|
19
|
+
|
|
20
|
+
Supports both Brand API (retrieve comprehensive brand data) and
|
|
21
|
+
Brand Search API (find and search brands by name).
|
|
22
|
+
|
|
23
|
+
-- Brand API
|
|
24
|
+
|
|
25
|
+
api_key: str - your Brandfetch API key
|
|
26
|
+
|
|
27
|
+
-- Brand Search API
|
|
28
|
+
|
|
29
|
+
client_id: str - your Brandfetch Client ID
|
|
30
|
+
|
|
31
|
+
all: bool - if True, will use all tools
|
|
32
|
+
enable_search_by_identifier: bool - if True, will use search by identifier
|
|
33
|
+
enable_search_by_brand: bool - if True, will use search by brand
|
|
34
|
+
enable_asearch_by_identifier: bool - if True, will use async search by identifier
|
|
35
|
+
enable_asearch_by_brand: bool - if True, will use async search by brand
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
api_key: Optional[str] = None,
|
|
41
|
+
client_id: Optional[str] = None,
|
|
42
|
+
base_url: str = "https://api.brandfetch.io/v2",
|
|
43
|
+
timeout: Optional[float] = 20.0,
|
|
44
|
+
enable_search_by_identifier: bool = True,
|
|
45
|
+
enable_search_by_brand: bool = False,
|
|
46
|
+
all: bool = False,
|
|
47
|
+
async_tools: bool = False,
|
|
48
|
+
**kwargs,
|
|
49
|
+
):
|
|
50
|
+
self.api_key = api_key or getenv("BRANDFETCH_API_KEY")
|
|
51
|
+
self.client_id = client_id or getenv("BRANDFETCH_CLIENT_ID")
|
|
52
|
+
self.base_url = base_url
|
|
53
|
+
self.timeout = httpx.Timeout(timeout)
|
|
54
|
+
self.search_url = f"{self.base_url}/search"
|
|
55
|
+
self.brand_url = f"{self.base_url}/brands"
|
|
56
|
+
|
|
57
|
+
tools: list[Any] = []
|
|
58
|
+
# Backward-compat mapping: prefer new enable_* flags, but honor legacy toggles
|
|
59
|
+
if async_tools:
|
|
60
|
+
if all or enable_search_by_identifier:
|
|
61
|
+
tools.append(self.asearch_by_identifier)
|
|
62
|
+
if all or enable_search_by_brand:
|
|
63
|
+
tools.append(self.asearch_by_brand)
|
|
64
|
+
else:
|
|
65
|
+
if all or enable_search_by_identifier:
|
|
66
|
+
tools.append(self.search_by_identifier)
|
|
67
|
+
if all or enable_search_by_brand:
|
|
68
|
+
tools.append(self.search_by_brand)
|
|
69
|
+
name = kwargs.pop("name", "brandfetch_tools")
|
|
70
|
+
super().__init__(name=name, tools=tools, **kwargs)
|
|
71
|
+
|
|
72
|
+
async def asearch_by_identifier(self, identifier: str) -> dict[str, Any]:
|
|
73
|
+
"""
|
|
74
|
+
Search for brand data by identifier (domain, brand id, isin, stock ticker).
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
identifier: Options are you can use: Domain (nike.com), Brand ID (id_0dwKPKT), ISIN (US6541061031), Stock Ticker (NKE)
|
|
78
|
+
Returns:
|
|
79
|
+
Dict containing brand data including logos, colors, fonts, and other brand assets
|
|
80
|
+
|
|
81
|
+
Raises:
|
|
82
|
+
ValueError: If no API key is provided
|
|
83
|
+
"""
|
|
84
|
+
if not self.api_key:
|
|
85
|
+
raise ValueError("API key is required for brand search by identifier")
|
|
86
|
+
|
|
87
|
+
url = f"{self.brand_url}/{identifier}"
|
|
88
|
+
headers = {"Authorization": f"Bearer {self.api_key}"}
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
92
|
+
response = await client.get(url, headers=headers)
|
|
93
|
+
response.raise_for_status()
|
|
94
|
+
return response.json()
|
|
95
|
+
except httpx.HTTPStatusError as e:
|
|
96
|
+
if e.response.status_code == 404:
|
|
97
|
+
return {"error": f"Brand not found for identifier: {identifier}"}
|
|
98
|
+
elif e.response.status_code == 401:
|
|
99
|
+
return {"error": "Invalid API key"}
|
|
100
|
+
elif e.response.status_code == 429:
|
|
101
|
+
return {"error": "Rate limit exceeded"}
|
|
102
|
+
else:
|
|
103
|
+
return {"error": f"API error: {e.response.status_code}"}
|
|
104
|
+
except httpx.RequestError as e:
|
|
105
|
+
return {"error": f"Request failed: {str(e)}"}
|
|
106
|
+
|
|
107
|
+
def search_by_identifier(self, identifier: str) -> dict[str, Any]:
|
|
108
|
+
"""
|
|
109
|
+
Search for brand data by identifier (domain, brand id, isin, stock ticker).
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
identifier: Options are you can use: Domain (nike.com), Brand ID (id_0dwKPKT), ISIN (US6541061031), Stock Ticker (NKE)
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
Dict containing brand data including logos, colors, fonts, and other brand assets
|
|
116
|
+
|
|
117
|
+
Raises:
|
|
118
|
+
ValueError: If no API key is provided
|
|
119
|
+
"""
|
|
120
|
+
if not self.api_key:
|
|
121
|
+
raise ValueError("API key is required for brand search by identifier")
|
|
122
|
+
|
|
123
|
+
url = f"{self.brand_url}/{identifier}"
|
|
124
|
+
headers = {"Authorization": f"Bearer {self.api_key}"}
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
with httpx.Client(timeout=self.timeout) as client:
|
|
128
|
+
response = client.get(url, headers=headers)
|
|
129
|
+
response.raise_for_status()
|
|
130
|
+
return response.json()
|
|
131
|
+
except httpx.HTTPStatusError as e:
|
|
132
|
+
if e.response.status_code == 404:
|
|
133
|
+
return {"error": f"Brand not found for identifier: {identifier}"}
|
|
134
|
+
elif e.response.status_code == 401:
|
|
135
|
+
return {"error": "Invalid API key"}
|
|
136
|
+
elif e.response.status_code == 429:
|
|
137
|
+
return {"error": "Rate limit exceeded"}
|
|
138
|
+
else:
|
|
139
|
+
return {"error": f"API error: {e.response.status_code}"}
|
|
140
|
+
except httpx.RequestError as e:
|
|
141
|
+
return {"error": f"Request failed: {str(e)}"}
|
|
142
|
+
|
|
143
|
+
async def asearch_by_brand(self, name: str) -> dict[str, Any]:
|
|
144
|
+
"""
|
|
145
|
+
Search for brands by name using the Brand Search API - can give you the right brand id to use for the brand api.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
name: Brand name to search for (e.g., 'Google', 'Apple')
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Dict containing search results with brand matches
|
|
152
|
+
|
|
153
|
+
Raises:
|
|
154
|
+
ValueError: If no client ID is provided
|
|
155
|
+
"""
|
|
156
|
+
if not self.client_id:
|
|
157
|
+
raise ValueError("Client ID is required for brand search by name")
|
|
158
|
+
|
|
159
|
+
url = f"{self.search_url}/{name}"
|
|
160
|
+
params = {"c": self.client_id}
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
164
|
+
response = await client.get(url, params=params)
|
|
165
|
+
response.raise_for_status()
|
|
166
|
+
return response.json()
|
|
167
|
+
except httpx.HTTPStatusError as e:
|
|
168
|
+
if e.response.status_code == 404:
|
|
169
|
+
return {"error": f"No brands found for name: {name}"}
|
|
170
|
+
elif e.response.status_code == 401:
|
|
171
|
+
return {"error": "Invalid client ID"}
|
|
172
|
+
elif e.response.status_code == 429:
|
|
173
|
+
return {"error": "Rate limit exceeded"}
|
|
174
|
+
else:
|
|
175
|
+
return {"error": f"API error: {e.response.status_code}"}
|
|
176
|
+
except httpx.RequestError as e:
|
|
177
|
+
return {"error": f"Request failed: {str(e)}"}
|
|
178
|
+
|
|
179
|
+
def search_by_brand(self, name: str) -> dict[str, Any]:
|
|
180
|
+
"""
|
|
181
|
+
Search for brands by name using the Brand Search API - can give you the right brand id to use for the brand api.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
name: Brand name to search for (e.g., 'Google', 'Apple')
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Dict containing search results with brand matches
|
|
188
|
+
|
|
189
|
+
Raises:
|
|
190
|
+
ValueError: If no client ID is provided
|
|
191
|
+
"""
|
|
192
|
+
if not self.client_id:
|
|
193
|
+
raise ValueError("Client ID is required for brand search by name")
|
|
194
|
+
|
|
195
|
+
url = f"{self.search_url}/{name}"
|
|
196
|
+
params = {"c": self.client_id}
|
|
197
|
+
|
|
198
|
+
try:
|
|
199
|
+
with httpx.Client(timeout=self.timeout) as client:
|
|
200
|
+
response = client.get(url, params=params)
|
|
201
|
+
response.raise_for_status()
|
|
202
|
+
return response.json()
|
|
203
|
+
except httpx.HTTPStatusError as e:
|
|
204
|
+
if e.response.status_code == 404:
|
|
205
|
+
return {"error": f"No brands found for name: {name}"}
|
|
206
|
+
elif e.response.status_code == 401:
|
|
207
|
+
return {"error": "Invalid client ID"}
|
|
208
|
+
elif e.response.status_code == 429:
|
|
209
|
+
return {"error": "Rate limit exceeded"}
|
|
210
|
+
else:
|
|
211
|
+
return {"error": f"API error: {e.response.status_code}"}
|
|
212
|
+
except httpx.RequestError as e:
|
|
213
|
+
return {"error": f"Request failed: {str(e)}"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from os import getenv
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from agno.tools import Toolkit
|
|
6
|
+
from agno.utils.log import log_info
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from brave import Brave
|
|
10
|
+
except ImportError:
|
|
11
|
+
raise ImportError("`brave-search` not installed. Please install using `pip install brave-search`")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BraveSearchTools(Toolkit):
|
|
15
|
+
"""
|
|
16
|
+
BraveSearch is a toolkit for searching Brave easily.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
api_key (str, optional): Brave API key. If not provided, will use BRAVE_API_KEY environment variable.
|
|
20
|
+
fixed_max_results (Optional[int]): A fixed number of maximum results.
|
|
21
|
+
fixed_language (Optional[str]): A fixed language for the search results.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
api_key: Optional[str] = None,
|
|
27
|
+
fixed_max_results: Optional[int] = None,
|
|
28
|
+
fixed_language: Optional[str] = None,
|
|
29
|
+
enable_brave_search: bool = True,
|
|
30
|
+
all: bool = False,
|
|
31
|
+
**kwargs,
|
|
32
|
+
):
|
|
33
|
+
self.api_key = api_key or getenv("BRAVE_API_KEY")
|
|
34
|
+
if not self.api_key:
|
|
35
|
+
raise ValueError("BRAVE_API_KEY is required. Please set the BRAVE_API_KEY environment variable.")
|
|
36
|
+
|
|
37
|
+
self.fixed_max_results = fixed_max_results
|
|
38
|
+
self.fixed_language = fixed_language
|
|
39
|
+
|
|
40
|
+
self.brave_client = Brave(api_key=self.api_key)
|
|
41
|
+
|
|
42
|
+
tools = []
|
|
43
|
+
if all or enable_brave_search:
|
|
44
|
+
tools.append(self.brave_search)
|
|
45
|
+
|
|
46
|
+
super().__init__(
|
|
47
|
+
name="brave_search",
|
|
48
|
+
tools=tools,
|
|
49
|
+
**kwargs,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
def brave_search(
|
|
53
|
+
self,
|
|
54
|
+
query: str,
|
|
55
|
+
max_results: int = 5,
|
|
56
|
+
country: str = "US",
|
|
57
|
+
search_lang: str = "en",
|
|
58
|
+
) -> str:
|
|
59
|
+
"""
|
|
60
|
+
Search Brave for the specified query and return the results.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
query (str): The query to search for.
|
|
64
|
+
max_results (int, optional): The maximum number of results to return. Default is 5.
|
|
65
|
+
country (str, optional): The country code for search results. Default is "US".
|
|
66
|
+
search_lang (str, optional): The language of the search results. Default is "en".
|
|
67
|
+
Returns:
|
|
68
|
+
str: A JSON formatted string containing the search results.
|
|
69
|
+
"""
|
|
70
|
+
final_max_results = self.fixed_max_results if self.fixed_max_results is not None else max_results
|
|
71
|
+
final_search_lang = self.fixed_language if self.fixed_language is not None else search_lang
|
|
72
|
+
|
|
73
|
+
if not query:
|
|
74
|
+
return json.dumps({"error": "Please provide a query to search for"})
|
|
75
|
+
|
|
76
|
+
log_info(f"Searching Brave for: {query}")
|
|
77
|
+
|
|
78
|
+
search_params = {
|
|
79
|
+
"q": query,
|
|
80
|
+
"count": final_max_results,
|
|
81
|
+
"country": country,
|
|
82
|
+
"search_lang": final_search_lang,
|
|
83
|
+
"result_filter": "web",
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
search_results = self.brave_client.search(**search_params)
|
|
87
|
+
|
|
88
|
+
filtered_results = {
|
|
89
|
+
"web_results": [],
|
|
90
|
+
"query": query,
|
|
91
|
+
"total_results": 0,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if hasattr(search_results, "web") and search_results.web:
|
|
95
|
+
web_results = []
|
|
96
|
+
for result in search_results.web.results:
|
|
97
|
+
web_result = {
|
|
98
|
+
"title": result.title,
|
|
99
|
+
"url": str(result.url),
|
|
100
|
+
"description": result.description,
|
|
101
|
+
}
|
|
102
|
+
web_results.append(web_result)
|
|
103
|
+
filtered_results["web_results"] = web_results
|
|
104
|
+
filtered_results["total_results"] = len(web_results)
|
|
105
|
+
|
|
106
|
+
return json.dumps(filtered_results, indent=2)
|
agno/tools/brightdata.py
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import json
|
|
3
|
+
from os import getenv
|
|
4
|
+
from typing import Any, Dict, List, Optional
|
|
5
|
+
from uuid import uuid4
|
|
6
|
+
|
|
7
|
+
from agno.agent import Agent
|
|
8
|
+
from agno.media import Image
|
|
9
|
+
from agno.tools import Toolkit
|
|
10
|
+
from agno.tools.function import ToolResult
|
|
11
|
+
from agno.utils.log import log_debug, log_error, log_info
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
import requests
|
|
15
|
+
except ImportError:
|
|
16
|
+
raise ImportError("`requests` not installed.")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BrightDataTools(Toolkit):
|
|
20
|
+
"""
|
|
21
|
+
BrightData is a toolkit for web scraping, screenshots, search engines, and web data feeds.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
api_key (Optional[str]): Bright Data API key. Retrieved from BRIGHT_DATA_API_KEY env variable if not provided.
|
|
25
|
+
enable_scrape_markdown (bool): Enable webpage scraping as Markdown. Default is True.
|
|
26
|
+
enable_screenshot (bool): Enable website screenshot capture. Default is True.
|
|
27
|
+
enable_search_engine (bool): Enable search engine functionality. Default is True.
|
|
28
|
+
enable_web_data_feed (bool): Enable web data feed retrieval. Default is True.
|
|
29
|
+
all (bool): Enable all tools. Overrides individual flags when True. Default is False.
|
|
30
|
+
serp_zone (str): SERP zone for search operations. Default is "serp_api".
|
|
31
|
+
web_unlocker_zone (str): Web unlocker zone for scraping operations. Default is "web_unlocker1".
|
|
32
|
+
verbose (bool): Enable verbose logging. Default is False.
|
|
33
|
+
timeout (int): Timeout in seconds for operations. Default is 600.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
api_key: Optional[str] = None,
|
|
39
|
+
enable_scrape_markdown: bool = True,
|
|
40
|
+
enable_screenshot: bool = True,
|
|
41
|
+
enable_search_engine: bool = True,
|
|
42
|
+
enable_web_data_feed: bool = True,
|
|
43
|
+
all: bool = False,
|
|
44
|
+
serp_zone: str = "serp_api",
|
|
45
|
+
web_unlocker_zone: str = "web_unlocker1",
|
|
46
|
+
verbose: bool = False,
|
|
47
|
+
timeout: int = 600,
|
|
48
|
+
**kwargs,
|
|
49
|
+
):
|
|
50
|
+
self.api_key = api_key or getenv("BRIGHT_DATA_API_KEY")
|
|
51
|
+
if not self.api_key:
|
|
52
|
+
log_error("No Bright Data API key provided")
|
|
53
|
+
raise ValueError(
|
|
54
|
+
"No Bright Data API key provided. Please provide an api_key or set the BRIGHT_DATA_API_KEY environment variable."
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
self.verbose = verbose
|
|
58
|
+
self.endpoint = "https://api.brightdata.com/request"
|
|
59
|
+
self.headers = {
|
|
60
|
+
"Content-Type": "application/json",
|
|
61
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
62
|
+
}
|
|
63
|
+
self.web_unlocker_zone = getenv("BRIGHT_DATA_WEB_UNLOCKER_ZONE", web_unlocker_zone)
|
|
64
|
+
self.serp_zone = getenv("BRIGHT_DATA_SERP_ZONE", serp_zone)
|
|
65
|
+
self.timeout = timeout
|
|
66
|
+
|
|
67
|
+
tools: List[Any] = []
|
|
68
|
+
if all or enable_scrape_markdown:
|
|
69
|
+
tools.append(self.scrape_as_markdown)
|
|
70
|
+
if all or enable_screenshot:
|
|
71
|
+
tools.append(self.get_screenshot)
|
|
72
|
+
if all or enable_search_engine:
|
|
73
|
+
tools.append(self.search_engine)
|
|
74
|
+
if all or enable_web_data_feed:
|
|
75
|
+
tools.append(self.web_data_feed)
|
|
76
|
+
|
|
77
|
+
super().__init__(name="brightdata_tools", tools=tools, **kwargs)
|
|
78
|
+
|
|
79
|
+
def _make_request(self, payload: Dict) -> str:
|
|
80
|
+
"""Make a request to Bright Data API."""
|
|
81
|
+
try:
|
|
82
|
+
if self.verbose:
|
|
83
|
+
log_info(f"[Bright Data] Request: {payload['url']}")
|
|
84
|
+
|
|
85
|
+
response = requests.post(self.endpoint, headers=self.headers, data=json.dumps(payload))
|
|
86
|
+
|
|
87
|
+
if response.status_code != 200:
|
|
88
|
+
raise Exception(f"Failed to scrape: {response.status_code} - {response.text}")
|
|
89
|
+
|
|
90
|
+
return response.text
|
|
91
|
+
except Exception as e:
|
|
92
|
+
raise Exception(f"Request failed: {e}")
|
|
93
|
+
|
|
94
|
+
def scrape_as_markdown(self, url: str) -> str:
|
|
95
|
+
"""
|
|
96
|
+
Scrape a webpage and return content in Markdown format.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
url (str): URL to scrape
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
str: Scraped content as Markdown
|
|
103
|
+
"""
|
|
104
|
+
try:
|
|
105
|
+
if not self.api_key:
|
|
106
|
+
return "Please provide a Bright Data API key"
|
|
107
|
+
if not url:
|
|
108
|
+
return "Please provide a URL to scrape"
|
|
109
|
+
|
|
110
|
+
log_info(f"Scraping URL as Markdown: {url}")
|
|
111
|
+
|
|
112
|
+
payload = {
|
|
113
|
+
"url": url,
|
|
114
|
+
"zone": self.web_unlocker_zone,
|
|
115
|
+
"format": "raw",
|
|
116
|
+
"data_format": "markdown",
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
content = self._make_request(payload)
|
|
120
|
+
return content
|
|
121
|
+
except Exception as e:
|
|
122
|
+
return f"Error scraping URL {url}: {e}"
|
|
123
|
+
|
|
124
|
+
def get_screenshot(self, agent: Agent, url: str, output_path: str = "screenshot.png") -> ToolResult:
|
|
125
|
+
"""
|
|
126
|
+
Capture a screenshot of a webpage
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
url (str): URL to screenshot
|
|
130
|
+
output_path (str): Output path for the screenshot (not used, kept for compatibility)
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
ToolResult: Contains the screenshot image or error message.
|
|
134
|
+
"""
|
|
135
|
+
try:
|
|
136
|
+
if not self.api_key:
|
|
137
|
+
return ToolResult(content="Please provide a Bright Data API key")
|
|
138
|
+
if not url:
|
|
139
|
+
return ToolResult(content="Please provide a URL to screenshot")
|
|
140
|
+
|
|
141
|
+
log_info(f"Taking screenshot of: {url}")
|
|
142
|
+
|
|
143
|
+
payload = {
|
|
144
|
+
"url": url,
|
|
145
|
+
"zone": self.web_unlocker_zone,
|
|
146
|
+
"format": "raw",
|
|
147
|
+
"data_format": "screenshot",
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
response = requests.post(self.endpoint, headers=self.headers, data=json.dumps(payload))
|
|
151
|
+
|
|
152
|
+
if response.status_code != 200:
|
|
153
|
+
raise Exception(f"Error {response.status_code}: {response.text}")
|
|
154
|
+
|
|
155
|
+
image_bytes = response.content
|
|
156
|
+
base64_encoded_image = base64.b64encode(image_bytes).decode("utf-8")
|
|
157
|
+
log_debug(f"Base64 encoded image: {type(base64_encoded_image)}")
|
|
158
|
+
|
|
159
|
+
media_id = str(uuid4())
|
|
160
|
+
|
|
161
|
+
# Create Image for the screenshot
|
|
162
|
+
image_artifact = Image(
|
|
163
|
+
id=media_id,
|
|
164
|
+
content=base64_encoded_image.encode("utf-8"),
|
|
165
|
+
mime_type="image/png",
|
|
166
|
+
original_prompt=f"Screenshot of {url}",
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
log_debug(f"Screenshot captured and added as artifact with ID: {media_id}")
|
|
170
|
+
return ToolResult(
|
|
171
|
+
content=f"Screenshot captured and added as artifact with ID: {media_id}", images=[image_artifact]
|
|
172
|
+
)
|
|
173
|
+
except Exception as e:
|
|
174
|
+
return ToolResult(content=f"Error taking screenshot of {url}: {e}")
|
|
175
|
+
|
|
176
|
+
def search_engine(
|
|
177
|
+
self,
|
|
178
|
+
query: str,
|
|
179
|
+
engine: str = "google",
|
|
180
|
+
num_results: int = 10,
|
|
181
|
+
language: Optional[str] = None,
|
|
182
|
+
country_code: Optional[str] = None,
|
|
183
|
+
) -> str:
|
|
184
|
+
"""
|
|
185
|
+
Search using Google, Bing, or Yandex and return results in Markdown.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
query (str): Search query
|
|
189
|
+
engine (str): Search engine - 'google', 'bing', or 'yandex'
|
|
190
|
+
num_results (int): Number of results to return
|
|
191
|
+
language (Optional[str]): Two-letter language code
|
|
192
|
+
country_code (Optional[str]): Two-letter country code
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
str: Search results as Markdown
|
|
196
|
+
"""
|
|
197
|
+
try:
|
|
198
|
+
if not self.api_key:
|
|
199
|
+
return "Please provide a Bright Data API key"
|
|
200
|
+
if not query:
|
|
201
|
+
return "Please provide a query to search for"
|
|
202
|
+
|
|
203
|
+
log_info(f"Searching {engine} for: {query}")
|
|
204
|
+
|
|
205
|
+
from urllib.parse import quote
|
|
206
|
+
|
|
207
|
+
encoded_query = quote(query)
|
|
208
|
+
|
|
209
|
+
base_urls = {
|
|
210
|
+
"google": f"https://www.google.com/search?q={encoded_query}",
|
|
211
|
+
"bing": f"https://www.bing.com/search?q={encoded_query}",
|
|
212
|
+
"yandex": f"https://yandex.com/search/?text={encoded_query}",
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if engine not in base_urls:
|
|
216
|
+
return f"Unsupported search engine: {engine}. Use 'google', 'bing', or 'yandex'"
|
|
217
|
+
|
|
218
|
+
search_url = base_urls[engine]
|
|
219
|
+
|
|
220
|
+
if engine == "google":
|
|
221
|
+
params = []
|
|
222
|
+
if language:
|
|
223
|
+
params.append(f"hl={language}")
|
|
224
|
+
if country_code:
|
|
225
|
+
params.append(f"gl={country_code}")
|
|
226
|
+
if num_results:
|
|
227
|
+
params.append(f"num={num_results}")
|
|
228
|
+
|
|
229
|
+
if params:
|
|
230
|
+
search_url += "&" + "&".join(params)
|
|
231
|
+
|
|
232
|
+
payload = {
|
|
233
|
+
"url": search_url,
|
|
234
|
+
"zone": self.serp_zone,
|
|
235
|
+
"format": "raw",
|
|
236
|
+
"data_format": "markdown",
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
content = self._make_request(payload)
|
|
240
|
+
return content
|
|
241
|
+
except Exception as e:
|
|
242
|
+
return f"Error searching for query {query}: {e}"
|
|
243
|
+
|
|
244
|
+
def web_data_feed(
|
|
245
|
+
self,
|
|
246
|
+
source_type: str,
|
|
247
|
+
url: str,
|
|
248
|
+
num_of_reviews: Optional[int] = None,
|
|
249
|
+
) -> str:
|
|
250
|
+
"""
|
|
251
|
+
Retrieve structured web data from various sources like LinkedIn, Amazon, Instagram, etc.
|
|
252
|
+
|
|
253
|
+
Args:
|
|
254
|
+
source_type (str): Type of data source (e.g., 'linkedin_person_profile', 'amazon_product')
|
|
255
|
+
url (str): URL of the web resource to retrieve data from
|
|
256
|
+
num_of_reviews (Optional[int]): Number of reviews to retrieve
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
str: Structured data from the requested source as JSON
|
|
260
|
+
"""
|
|
261
|
+
try:
|
|
262
|
+
if not self.api_key:
|
|
263
|
+
return "Please provide a Bright Data API key"
|
|
264
|
+
if not url:
|
|
265
|
+
return "Please provide a URL to retrieve data from"
|
|
266
|
+
|
|
267
|
+
log_info(f"Retrieving {source_type} data from: {url}")
|
|
268
|
+
|
|
269
|
+
datasets = {
|
|
270
|
+
"amazon_product": "gd_l7q7dkf244hwjntr0",
|
|
271
|
+
"amazon_product_reviews": "gd_le8e811kzy4ggddlq",
|
|
272
|
+
"amazon_product_search": "gd_lwdb4vjm1ehb499uxs",
|
|
273
|
+
"walmart_product": "gd_l95fol7l1ru6rlo116",
|
|
274
|
+
"walmart_seller": "gd_m7ke48w81ocyu4hhz0",
|
|
275
|
+
"ebay_product": "gd_ltr9mjt81n0zzdk1fb",
|
|
276
|
+
"homedepot_products": "gd_lmusivh019i7g97q2n",
|
|
277
|
+
"zara_products": "gd_lct4vafw1tgx27d4o0",
|
|
278
|
+
"etsy_products": "gd_ltppk0jdv1jqz25mz",
|
|
279
|
+
"bestbuy_products": "gd_ltre1jqe1jfr7cccf",
|
|
280
|
+
"linkedin_person_profile": "gd_l1viktl72bvl7bjuj0",
|
|
281
|
+
"linkedin_company_profile": "gd_l1vikfnt1wgvvqz95w",
|
|
282
|
+
"linkedin_job_listings": "gd_lpfll7v5hcqtkxl6l",
|
|
283
|
+
"linkedin_posts": "gd_lyy3tktm25m4avu764",
|
|
284
|
+
"linkedin_people_search": "gd_m8d03he47z8nwb5xc",
|
|
285
|
+
"crunchbase_company": "gd_l1vijqt9jfj7olije",
|
|
286
|
+
"zoominfo_company_profile": "gd_m0ci4a4ivx3j5l6nx",
|
|
287
|
+
"instagram_profiles": "gd_l1vikfch901nx3by4",
|
|
288
|
+
"instagram_posts": "gd_lk5ns7kz21pck8jpis",
|
|
289
|
+
"instagram_reels": "gd_lyclm20il4r5helnj",
|
|
290
|
+
"instagram_comments": "gd_ltppn085pokosxh13",
|
|
291
|
+
"facebook_posts": "gd_lyclm1571iy3mv57zw",
|
|
292
|
+
"facebook_marketplace_listings": "gd_lvt9iwuh6fbcwmx1a",
|
|
293
|
+
"facebook_company_reviews": "gd_m0dtqpiu1mbcyc2g86",
|
|
294
|
+
"facebook_events": "gd_m14sd0to1jz48ppm51",
|
|
295
|
+
"tiktok_profiles": "gd_l1villgoiiidt09ci",
|
|
296
|
+
"tiktok_posts": "gd_lu702nij2f790tmv9h",
|
|
297
|
+
"tiktok_shop": "gd_m45m1u911dsa4274pi",
|
|
298
|
+
"tiktok_comments": "gd_lkf2st302ap89utw5k",
|
|
299
|
+
"google_maps_reviews": "gd_luzfs1dn2oa0teb81",
|
|
300
|
+
"google_shopping": "gd_ltppk50q18kdw67omz",
|
|
301
|
+
"google_play_store": "gd_lsk382l8xei8vzm4u",
|
|
302
|
+
"apple_app_store": "gd_lsk9ki3u2iishmwrui",
|
|
303
|
+
"reuter_news": "gd_lyptx9h74wtlvpnfu",
|
|
304
|
+
"github_repository_file": "gd_lyrexgxc24b3d4imjt",
|
|
305
|
+
"yahoo_finance_business": "gd_lmrpz3vxmz972ghd7",
|
|
306
|
+
"x_posts": "gd_lwxkxvnf1cynvib9co",
|
|
307
|
+
"zillow_properties_listing": "gd_lfqkr8wm13ixtbd8f5",
|
|
308
|
+
"booking_hotel_listings": "gd_m5mbdl081229ln6t4a",
|
|
309
|
+
"youtube_profiles": "gd_lk538t2k2p1k3oos71",
|
|
310
|
+
"youtube_comments": "gd_lk9q0ew71spt1mxywf",
|
|
311
|
+
"reddit_posts": "gd_lvz8ah06191smkebj4",
|
|
312
|
+
"youtube_videos": "gd_m5mbdl081229ln6t4a",
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if source_type not in datasets:
|
|
316
|
+
valid_sources = ", ".join(datasets.keys())
|
|
317
|
+
return f"Invalid source_type: {source_type}. Valid options are: {valid_sources}"
|
|
318
|
+
|
|
319
|
+
dataset_id = datasets[source_type]
|
|
320
|
+
|
|
321
|
+
request_data = {"url": url}
|
|
322
|
+
if source_type == "facebook_company_reviews" and num_of_reviews is not None:
|
|
323
|
+
request_data["num_of_reviews"] = str(num_of_reviews)
|
|
324
|
+
|
|
325
|
+
trigger_response = requests.post(
|
|
326
|
+
"https://api.brightdata.com/datasets/v3/trigger",
|
|
327
|
+
params={"dataset_id": dataset_id, "include_errors": "true"},
|
|
328
|
+
headers=self.headers,
|
|
329
|
+
json=[request_data],
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
trigger_data = trigger_response.json()
|
|
333
|
+
if not trigger_data.get("snapshot_id"):
|
|
334
|
+
return "No snapshot ID returned from trigger request"
|
|
335
|
+
|
|
336
|
+
snapshot_id = trigger_data["snapshot_id"]
|
|
337
|
+
|
|
338
|
+
import time
|
|
339
|
+
|
|
340
|
+
attempts = 0
|
|
341
|
+
max_attempts = self.timeout
|
|
342
|
+
|
|
343
|
+
while attempts < max_attempts:
|
|
344
|
+
try:
|
|
345
|
+
snapshot_response = requests.get(
|
|
346
|
+
f"https://api.brightdata.com/datasets/v3/snapshot/{snapshot_id}",
|
|
347
|
+
params={"format": "json"},
|
|
348
|
+
headers=self.headers,
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
snapshot_data = snapshot_response.json()
|
|
352
|
+
|
|
353
|
+
if isinstance(snapshot_data, dict) and snapshot_data.get("status") == "running":
|
|
354
|
+
attempts += 1
|
|
355
|
+
time.sleep(1)
|
|
356
|
+
continue
|
|
357
|
+
|
|
358
|
+
return json.dumps(snapshot_data)
|
|
359
|
+
|
|
360
|
+
except Exception:
|
|
361
|
+
attempts += 1
|
|
362
|
+
time.sleep(1)
|
|
363
|
+
|
|
364
|
+
return f"Timeout after {max_attempts} seconds waiting for {source_type} data"
|
|
365
|
+
|
|
366
|
+
except Exception as e:
|
|
367
|
+
return f"Error retrieving {source_type} data from {url}: {e}"
|