agno 0.1.2__py3-none-any.whl → 2.3.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agno/__init__.py +8 -0
- agno/agent/__init__.py +44 -5
- agno/agent/agent.py +10531 -2975
- agno/api/agent.py +14 -53
- agno/api/api.py +7 -46
- agno/api/evals.py +22 -0
- agno/api/os.py +17 -0
- agno/api/routes.py +6 -25
- agno/api/schemas/__init__.py +9 -0
- agno/api/schemas/agent.py +6 -9
- agno/api/schemas/evals.py +16 -0
- agno/api/schemas/os.py +14 -0
- agno/api/schemas/team.py +10 -10
- agno/api/schemas/utils.py +21 -0
- agno/api/schemas/workflows.py +16 -0
- agno/api/settings.py +53 -0
- agno/api/team.py +22 -26
- agno/api/workflow.py +28 -0
- agno/cloud/aws/base.py +214 -0
- agno/cloud/aws/s3/__init__.py +2 -0
- agno/cloud/aws/s3/api_client.py +43 -0
- agno/cloud/aws/s3/bucket.py +195 -0
- agno/cloud/aws/s3/object.py +57 -0
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/__init__.py +24 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +946 -0
- agno/db/dynamo/__init__.py +3 -0
- agno/db/dynamo/dynamo.py +2781 -0
- agno/db/dynamo/schemas.py +442 -0
- agno/db/dynamo/utils.py +743 -0
- agno/db/firestore/__init__.py +3 -0
- agno/db/firestore/firestore.py +2379 -0
- agno/db/firestore/schemas.py +181 -0
- agno/db/firestore/utils.py +376 -0
- agno/db/gcs_json/__init__.py +3 -0
- agno/db/gcs_json/gcs_json_db.py +1791 -0
- agno/db/gcs_json/utils.py +228 -0
- agno/db/in_memory/__init__.py +3 -0
- agno/db/in_memory/in_memory_db.py +1312 -0
- agno/db/in_memory/utils.py +230 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1777 -0
- agno/db/json/utils.py +230 -0
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +635 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +17 -0
- agno/db/mongo/async_mongo.py +2760 -0
- agno/db/mongo/mongo.py +2597 -0
- agno/db/mongo/schemas.py +119 -0
- agno/db/mongo/utils.py +276 -0
- agno/db/mysql/__init__.py +4 -0
- agno/db/mysql/async_mysql.py +2912 -0
- agno/db/mysql/mysql.py +2923 -0
- agno/db/mysql/schemas.py +186 -0
- agno/db/mysql/utils.py +488 -0
- agno/db/postgres/__init__.py +4 -0
- agno/db/postgres/async_postgres.py +2579 -0
- agno/db/postgres/postgres.py +2870 -0
- agno/db/postgres/schemas.py +187 -0
- agno/db/postgres/utils.py +442 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +2141 -0
- agno/db/redis/schemas.py +159 -0
- agno/db/redis/utils.py +346 -0
- agno/db/schemas/__init__.py +4 -0
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/evals.py +34 -0
- agno/db/schemas/knowledge.py +40 -0
- agno/db/schemas/memory.py +61 -0
- agno/db/singlestore/__init__.py +3 -0
- agno/db/singlestore/schemas.py +179 -0
- agno/db/singlestore/singlestore.py +2877 -0
- agno/db/singlestore/utils.py +384 -0
- agno/db/sqlite/__init__.py +4 -0
- agno/db/sqlite/async_sqlite.py +2911 -0
- agno/db/sqlite/schemas.py +181 -0
- agno/db/sqlite/sqlite.py +2908 -0
- agno/db/sqlite/utils.py +429 -0
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +334 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1908 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +118 -0
- agno/eval/__init__.py +24 -0
- agno/eval/accuracy.py +666 -276
- agno/eval/agent_as_judge.py +861 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +779 -0
- agno/eval/reliability.py +241 -62
- agno/eval/utils.py +120 -0
- agno/exceptions.py +143 -1
- agno/filters.py +354 -0
- agno/guardrails/__init__.py +6 -0
- agno/guardrails/base.py +19 -0
- agno/guardrails/openai.py +144 -0
- agno/guardrails/pii.py +94 -0
- agno/guardrails/prompt_injection.py +52 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/__init__.py +3 -0
- agno/integrations/discord/client.py +203 -0
- agno/knowledge/__init__.py +5 -1
- agno/{document → knowledge}/chunking/agentic.py +22 -14
- agno/{document → knowledge}/chunking/document.py +2 -2
- agno/{document → knowledge}/chunking/fixed.py +7 -6
- agno/knowledge/chunking/markdown.py +151 -0
- agno/{document → knowledge}/chunking/recursive.py +15 -3
- agno/knowledge/chunking/row.py +39 -0
- agno/knowledge/chunking/semantic.py +91 -0
- agno/knowledge/chunking/strategy.py +165 -0
- agno/knowledge/content.py +74 -0
- agno/knowledge/document/__init__.py +5 -0
- agno/{document → knowledge/document}/base.py +12 -2
- agno/knowledge/embedder/__init__.py +5 -0
- agno/knowledge/embedder/aws_bedrock.py +343 -0
- agno/knowledge/embedder/azure_openai.py +210 -0
- agno/{embedder → knowledge/embedder}/base.py +8 -0
- agno/knowledge/embedder/cohere.py +323 -0
- agno/knowledge/embedder/fastembed.py +62 -0
- agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
- agno/knowledge/embedder/google.py +258 -0
- agno/knowledge/embedder/huggingface.py +94 -0
- agno/knowledge/embedder/jina.py +182 -0
- agno/knowledge/embedder/langdb.py +22 -0
- agno/knowledge/embedder/mistral.py +206 -0
- agno/knowledge/embedder/nebius.py +13 -0
- agno/knowledge/embedder/ollama.py +154 -0
- agno/knowledge/embedder/openai.py +195 -0
- agno/knowledge/embedder/sentence_transformer.py +63 -0
- agno/{embedder → knowledge/embedder}/together.py +1 -1
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +165 -0
- agno/knowledge/knowledge.py +3006 -0
- agno/knowledge/reader/__init__.py +7 -0
- agno/knowledge/reader/arxiv_reader.py +81 -0
- agno/knowledge/reader/base.py +95 -0
- agno/knowledge/reader/csv_reader.py +164 -0
- agno/knowledge/reader/docx_reader.py +82 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/firecrawl_reader.py +201 -0
- agno/knowledge/reader/json_reader.py +88 -0
- agno/knowledge/reader/markdown_reader.py +137 -0
- agno/knowledge/reader/pdf_reader.py +431 -0
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +313 -0
- agno/knowledge/reader/s3_reader.py +89 -0
- agno/knowledge/reader/tavily_reader.py +193 -0
- agno/knowledge/reader/text_reader.py +127 -0
- agno/knowledge/reader/web_search_reader.py +325 -0
- agno/knowledge/reader/website_reader.py +455 -0
- agno/knowledge/reader/wikipedia_reader.py +91 -0
- agno/knowledge/reader/youtube_reader.py +78 -0
- agno/knowledge/remote_content/remote_content.py +88 -0
- agno/knowledge/reranker/__init__.py +3 -0
- agno/{reranker → knowledge/reranker}/base.py +1 -1
- agno/{reranker → knowledge/reranker}/cohere.py +2 -2
- agno/knowledge/reranker/infinity.py +195 -0
- agno/knowledge/reranker/sentence_transformer.py +54 -0
- agno/knowledge/types.py +39 -0
- agno/knowledge/utils.py +234 -0
- agno/media.py +439 -95
- agno/memory/__init__.py +16 -3
- agno/memory/manager.py +1474 -123
- agno/memory/strategies/__init__.py +15 -0
- agno/memory/strategies/base.py +66 -0
- agno/memory/strategies/summarize.py +196 -0
- agno/memory/strategies/types.py +37 -0
- agno/models/aimlapi/__init__.py +5 -0
- agno/models/aimlapi/aimlapi.py +62 -0
- agno/models/anthropic/__init__.py +4 -0
- agno/models/anthropic/claude.py +960 -496
- agno/models/aws/__init__.py +15 -0
- agno/models/aws/bedrock.py +686 -451
- agno/models/aws/claude.py +190 -183
- agno/models/azure/__init__.py +18 -1
- agno/models/azure/ai_foundry.py +489 -0
- agno/models/azure/openai_chat.py +89 -40
- agno/models/base.py +2477 -550
- agno/models/cerebras/__init__.py +12 -0
- agno/models/cerebras/cerebras.py +565 -0
- agno/models/cerebras/cerebras_openai.py +131 -0
- agno/models/cohere/__init__.py +4 -0
- agno/models/cohere/chat.py +306 -492
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +74 -0
- agno/models/dashscope/__init__.py +5 -0
- agno/models/dashscope/dashscope.py +90 -0
- agno/models/deepinfra/__init__.py +5 -0
- agno/models/deepinfra/deepinfra.py +45 -0
- agno/models/deepseek/__init__.py +4 -0
- agno/models/deepseek/deepseek.py +110 -9
- agno/models/fireworks/__init__.py +4 -0
- agno/models/fireworks/fireworks.py +19 -22
- agno/models/google/__init__.py +3 -7
- agno/models/google/gemini.py +1717 -662
- agno/models/google/utils.py +22 -0
- agno/models/groq/__init__.py +4 -0
- agno/models/groq/groq.py +391 -666
- agno/models/huggingface/__init__.py +4 -0
- agno/models/huggingface/huggingface.py +266 -538
- agno/models/ibm/__init__.py +5 -0
- agno/models/ibm/watsonx.py +432 -0
- agno/models/internlm/__init__.py +3 -0
- agno/models/internlm/internlm.py +20 -3
- agno/models/langdb/__init__.py +1 -0
- agno/models/langdb/langdb.py +60 -0
- agno/models/litellm/__init__.py +14 -0
- agno/models/litellm/chat.py +503 -0
- agno/models/litellm/litellm_openai.py +42 -0
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/lmstudio/__init__.py +5 -0
- agno/models/lmstudio/lmstudio.py +25 -0
- agno/models/message.py +361 -39
- agno/models/meta/__init__.py +12 -0
- agno/models/meta/llama.py +502 -0
- agno/models/meta/llama_openai.py +79 -0
- agno/models/metrics.py +120 -0
- agno/models/mistral/__init__.py +4 -0
- agno/models/mistral/mistral.py +293 -393
- agno/models/nebius/__init__.py +3 -0
- agno/models/nebius/nebius.py +53 -0
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/__init__.py +4 -0
- agno/models/nvidia/nvidia.py +22 -3
- agno/models/ollama/__init__.py +4 -2
- agno/models/ollama/chat.py +257 -492
- agno/models/openai/__init__.py +7 -0
- agno/models/openai/chat.py +725 -770
- agno/models/openai/like.py +16 -2
- agno/models/openai/responses.py +1121 -0
- agno/models/openrouter/__init__.py +4 -0
- agno/models/openrouter/openrouter.py +62 -5
- agno/models/perplexity/__init__.py +5 -0
- agno/models/perplexity/perplexity.py +203 -0
- agno/models/portkey/__init__.py +3 -0
- agno/models/portkey/portkey.py +82 -0
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +69 -0
- agno/models/response.py +177 -7
- agno/models/sambanova/__init__.py +4 -0
- agno/models/sambanova/sambanova.py +23 -4
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +42 -0
- agno/models/together/__init__.py +4 -0
- agno/models/together/together.py +21 -164
- agno/models/utils.py +266 -0
- agno/models/vercel/__init__.py +3 -0
- agno/models/vercel/v0.py +43 -0
- agno/models/vertexai/__init__.py +0 -1
- agno/models/vertexai/claude.py +190 -0
- agno/models/vllm/__init__.py +3 -0
- agno/models/vllm/vllm.py +83 -0
- agno/models/xai/__init__.py +2 -0
- agno/models/xai/xai.py +111 -7
- agno/os/__init__.py +3 -0
- agno/os/app.py +1027 -0
- agno/os/auth.py +244 -0
- agno/os/config.py +126 -0
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/a2a/__init__.py +3 -0
- agno/os/interfaces/a2a/a2a.py +42 -0
- agno/os/interfaces/a2a/router.py +249 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/__init__.py +3 -0
- agno/os/interfaces/agui/agui.py +47 -0
- agno/os/interfaces/agui/router.py +147 -0
- agno/os/interfaces/agui/utils.py +574 -0
- agno/os/interfaces/base.py +25 -0
- agno/os/interfaces/slack/__init__.py +3 -0
- agno/os/interfaces/slack/router.py +148 -0
- agno/os/interfaces/slack/security.py +30 -0
- agno/os/interfaces/slack/slack.py +47 -0
- agno/os/interfaces/whatsapp/__init__.py +3 -0
- agno/os/interfaces/whatsapp/router.py +210 -0
- agno/os/interfaces/whatsapp/security.py +55 -0
- agno/os/interfaces/whatsapp/whatsapp.py +36 -0
- agno/os/mcp.py +293 -0
- agno/os/middleware/__init__.py +9 -0
- agno/os/middleware/jwt.py +797 -0
- agno/os/router.py +258 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +599 -0
- agno/os/routers/agents/schema.py +261 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +450 -0
- agno/os/routers/evals/schemas.py +174 -0
- agno/os/routers/evals/utils.py +231 -0
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/__init__.py +3 -0
- agno/os/routers/knowledge/knowledge.py +1008 -0
- agno/os/routers/knowledge/schemas.py +178 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +661 -0
- agno/os/routers/memory/schemas.py +88 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +190 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +997 -0
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +512 -0
- agno/os/routers/teams/schema.py +257 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +499 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +624 -0
- agno/os/routers/workflows/schema.py +75 -0
- agno/os/schema.py +534 -0
- agno/os/scopes.py +469 -0
- agno/{playground → os}/settings.py +7 -15
- agno/os/utils.py +973 -0
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +67 -0
- agno/reasoning/deepseek.py +63 -0
- agno/reasoning/default.py +97 -0
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +71 -0
- agno/reasoning/helpers.py +24 -1
- agno/reasoning/ollama.py +67 -0
- agno/reasoning/openai.py +86 -0
- agno/reasoning/step.py +2 -1
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +822 -0
- agno/run/base.py +247 -0
- agno/run/cancel.py +81 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +767 -0
- agno/run/workflow.py +708 -0
- agno/session/__init__.py +10 -0
- agno/session/agent.py +260 -0
- agno/session/summary.py +265 -0
- agno/session/team.py +342 -0
- agno/session/workflow.py +501 -0
- agno/table.py +10 -0
- agno/team/__init__.py +37 -0
- agno/team/team.py +9536 -0
- agno/tools/__init__.py +7 -0
- agno/tools/agentql.py +120 -0
- agno/tools/airflow.py +22 -12
- agno/tools/api.py +122 -0
- agno/tools/apify.py +276 -83
- agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
- agno/tools/aws_lambda.py +28 -7
- agno/tools/aws_ses.py +66 -0
- agno/tools/baidusearch.py +11 -4
- agno/tools/bitbucket.py +292 -0
- agno/tools/brandfetch.py +213 -0
- agno/tools/bravesearch.py +106 -0
- agno/tools/brightdata.py +367 -0
- agno/tools/browserbase.py +209 -0
- agno/tools/calcom.py +32 -23
- agno/tools/calculator.py +24 -37
- agno/tools/cartesia.py +187 -0
- agno/tools/{clickup_tool.py → clickup.py} +17 -28
- agno/tools/confluence.py +91 -26
- agno/tools/crawl4ai.py +139 -43
- agno/tools/csv_toolkit.py +28 -22
- agno/tools/dalle.py +36 -22
- agno/tools/daytona.py +475 -0
- agno/tools/decorator.py +169 -14
- agno/tools/desi_vocal.py +23 -11
- agno/tools/discord.py +32 -29
- agno/tools/docker.py +716 -0
- agno/tools/duckdb.py +76 -81
- agno/tools/duckduckgo.py +43 -40
- agno/tools/e2b.py +703 -0
- agno/tools/eleven_labs.py +65 -54
- agno/tools/email.py +13 -5
- agno/tools/evm.py +129 -0
- agno/tools/exa.py +324 -42
- agno/tools/fal.py +39 -35
- agno/tools/file.py +196 -30
- agno/tools/file_generation.py +356 -0
- agno/tools/financial_datasets.py +288 -0
- agno/tools/firecrawl.py +108 -33
- agno/tools/function.py +960 -122
- agno/tools/giphy.py +34 -12
- agno/tools/github.py +1294 -97
- agno/tools/gmail.py +922 -0
- agno/tools/google_bigquery.py +117 -0
- agno/tools/google_drive.py +271 -0
- agno/tools/google_maps.py +253 -0
- agno/tools/googlecalendar.py +607 -107
- agno/tools/googlesheets.py +377 -0
- agno/tools/hackernews.py +20 -12
- agno/tools/jina.py +24 -14
- agno/tools/jira.py +48 -19
- agno/tools/knowledge.py +218 -0
- agno/tools/linear.py +82 -43
- agno/tools/linkup.py +58 -0
- agno/tools/local_file_system.py +15 -7
- agno/tools/lumalab.py +41 -26
- agno/tools/mcp/__init__.py +10 -0
- agno/tools/mcp/mcp.py +331 -0
- agno/tools/mcp/multi_mcp.py +347 -0
- agno/tools/mcp/params.py +24 -0
- agno/tools/mcp_toolbox.py +284 -0
- agno/tools/mem0.py +193 -0
- agno/tools/memory.py +419 -0
- agno/tools/mlx_transcribe.py +11 -9
- agno/tools/models/azure_openai.py +190 -0
- agno/tools/models/gemini.py +203 -0
- agno/tools/models/groq.py +158 -0
- agno/tools/models/morph.py +186 -0
- agno/tools/models/nebius.py +124 -0
- agno/tools/models_labs.py +163 -82
- agno/tools/moviepy_video.py +18 -13
- agno/tools/nano_banana.py +151 -0
- agno/tools/neo4j.py +134 -0
- agno/tools/newspaper.py +15 -4
- agno/tools/newspaper4k.py +19 -6
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +181 -17
- agno/tools/openbb.py +27 -20
- agno/tools/opencv.py +321 -0
- agno/tools/openweather.py +233 -0
- agno/tools/oxylabs.py +385 -0
- agno/tools/pandas.py +25 -15
- agno/tools/parallel.py +314 -0
- agno/tools/postgres.py +238 -185
- agno/tools/pubmed.py +125 -13
- agno/tools/python.py +48 -35
- agno/tools/reasoning.py +283 -0
- agno/tools/reddit.py +207 -29
- agno/tools/redshift.py +406 -0
- agno/tools/replicate.py +69 -26
- agno/tools/resend.py +11 -6
- agno/tools/scrapegraph.py +179 -19
- agno/tools/searxng.py +23 -31
- agno/tools/serpapi.py +15 -10
- agno/tools/serper.py +255 -0
- agno/tools/shell.py +23 -12
- agno/tools/shopify.py +1519 -0
- agno/tools/slack.py +56 -14
- agno/tools/sleep.py +8 -6
- agno/tools/spider.py +35 -11
- agno/tools/spotify.py +919 -0
- agno/tools/sql.py +34 -19
- agno/tools/tavily.py +158 -8
- agno/tools/telegram.py +18 -8
- agno/tools/todoist.py +218 -0
- agno/tools/toolkit.py +134 -9
- agno/tools/trafilatura.py +388 -0
- agno/tools/trello.py +25 -28
- agno/tools/twilio.py +18 -9
- agno/tools/user_control_flow.py +78 -0
- agno/tools/valyu.py +228 -0
- agno/tools/visualization.py +467 -0
- agno/tools/webbrowser.py +28 -0
- agno/tools/webex.py +76 -0
- agno/tools/website.py +23 -19
- agno/tools/webtools.py +45 -0
- agno/tools/whatsapp.py +286 -0
- agno/tools/wikipedia.py +28 -19
- agno/tools/workflow.py +285 -0
- agno/tools/{twitter.py → x.py} +142 -46
- agno/tools/yfinance.py +41 -39
- agno/tools/youtube.py +34 -17
- agno/tools/zendesk.py +15 -5
- agno/tools/zep.py +454 -0
- agno/tools/zoom.py +86 -37
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +157 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +111 -0
- agno/utils/agent.py +938 -0
- agno/utils/audio.py +37 -1
- agno/utils/certs.py +27 -0
- agno/utils/code_execution.py +11 -0
- agno/utils/common.py +103 -20
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +700 -0
- agno/utils/functions.py +107 -37
- agno/utils/gemini.py +426 -0
- agno/utils/hooks.py +171 -0
- agno/utils/http.py +185 -0
- agno/utils/json_schema.py +159 -37
- agno/utils/knowledge.py +36 -0
- agno/utils/location.py +19 -0
- agno/utils/log.py +221 -8
- agno/utils/mcp.py +214 -0
- agno/utils/media.py +335 -14
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +77 -2
- agno/utils/models/ai_foundry.py +50 -0
- agno/utils/models/claude.py +373 -0
- agno/utils/models/cohere.py +94 -0
- agno/utils/models/llama.py +85 -0
- agno/utils/models/mistral.py +100 -0
- agno/utils/models/openai_responses.py +140 -0
- agno/utils/models/schema_utils.py +153 -0
- agno/utils/models/watsonx.py +41 -0
- agno/utils/openai.py +257 -0
- agno/utils/pickle.py +1 -1
- agno/utils/pprint.py +124 -8
- agno/utils/print_response/agent.py +930 -0
- agno/utils/print_response/team.py +1914 -0
- agno/utils/print_response/workflow.py +1668 -0
- agno/utils/prompts.py +111 -0
- agno/utils/reasoning.py +108 -0
- agno/utils/response.py +163 -0
- agno/utils/serialize.py +32 -0
- agno/utils/shell.py +4 -4
- agno/utils/streamlit.py +487 -0
- agno/utils/string.py +204 -51
- agno/utils/team.py +139 -0
- agno/utils/timer.py +9 -2
- agno/utils/tokens.py +657 -0
- agno/utils/tools.py +19 -1
- agno/utils/whatsapp.py +305 -0
- agno/utils/yaml_io.py +3 -3
- agno/vectordb/__init__.py +2 -0
- agno/vectordb/base.py +87 -9
- agno/vectordb/cassandra/__init__.py +5 -1
- agno/vectordb/cassandra/cassandra.py +383 -27
- agno/vectordb/chroma/__init__.py +4 -0
- agno/vectordb/chroma/chromadb.py +748 -83
- agno/vectordb/clickhouse/__init__.py +7 -1
- agno/vectordb/clickhouse/clickhousedb.py +554 -53
- agno/vectordb/couchbase/__init__.py +3 -0
- agno/vectordb/couchbase/couchbase.py +1446 -0
- agno/vectordb/lancedb/__init__.py +5 -0
- agno/vectordb/lancedb/lance_db.py +730 -98
- agno/vectordb/langchaindb/__init__.py +5 -0
- agno/vectordb/langchaindb/langchaindb.py +163 -0
- agno/vectordb/lightrag/__init__.py +5 -0
- agno/vectordb/lightrag/lightrag.py +388 -0
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +166 -0
- agno/vectordb/milvus/__init__.py +3 -0
- agno/vectordb/milvus/milvus.py +966 -78
- agno/vectordb/mongodb/__init__.py +9 -1
- agno/vectordb/mongodb/mongodb.py +1175 -172
- agno/vectordb/pgvector/__init__.py +8 -0
- agno/vectordb/pgvector/pgvector.py +599 -115
- agno/vectordb/pineconedb/__init__.py +5 -1
- agno/vectordb/pineconedb/pineconedb.py +406 -43
- agno/vectordb/qdrant/__init__.py +4 -0
- agno/vectordb/qdrant/qdrant.py +914 -61
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +682 -0
- agno/vectordb/singlestore/__init__.py +8 -1
- agno/vectordb/singlestore/singlestore.py +771 -0
- agno/vectordb/surrealdb/__init__.py +3 -0
- agno/vectordb/surrealdb/surrealdb.py +663 -0
- agno/vectordb/upstashdb/__init__.py +5 -0
- agno/vectordb/upstashdb/upstashdb.py +718 -0
- agno/vectordb/weaviate/__init__.py +8 -0
- agno/vectordb/weaviate/index.py +15 -0
- agno/vectordb/weaviate/weaviate.py +1009 -0
- agno/workflow/__init__.py +23 -1
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +759 -0
- agno/workflow/loop.py +756 -0
- agno/workflow/parallel.py +853 -0
- agno/workflow/router.py +723 -0
- agno/workflow/step.py +1564 -0
- agno/workflow/steps.py +613 -0
- agno/workflow/types.py +556 -0
- agno/workflow/workflow.py +4327 -514
- agno-2.3.13.dist-info/METADATA +639 -0
- agno-2.3.13.dist-info/RECORD +613 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
- agno-2.3.13.dist-info/licenses/LICENSE +201 -0
- agno/api/playground.py +0 -91
- agno/api/schemas/playground.py +0 -22
- agno/api/schemas/user.py +0 -22
- agno/api/schemas/workspace.py +0 -46
- agno/api/user.py +0 -160
- agno/api/workspace.py +0 -151
- agno/cli/auth_server.py +0 -118
- agno/cli/config.py +0 -275
- agno/cli/console.py +0 -88
- agno/cli/credentials.py +0 -23
- agno/cli/entrypoint.py +0 -571
- agno/cli/operator.py +0 -355
- agno/cli/settings.py +0 -85
- agno/cli/ws/ws_cli.py +0 -817
- agno/constants.py +0 -13
- agno/document/__init__.py +0 -1
- agno/document/chunking/semantic.py +0 -47
- agno/document/chunking/strategy.py +0 -31
- agno/document/reader/__init__.py +0 -1
- agno/document/reader/arxiv_reader.py +0 -41
- agno/document/reader/base.py +0 -22
- agno/document/reader/csv_reader.py +0 -84
- agno/document/reader/docx_reader.py +0 -46
- agno/document/reader/firecrawl_reader.py +0 -99
- agno/document/reader/json_reader.py +0 -43
- agno/document/reader/pdf_reader.py +0 -219
- agno/document/reader/s3/pdf_reader.py +0 -46
- agno/document/reader/s3/text_reader.py +0 -51
- agno/document/reader/text_reader.py +0 -41
- agno/document/reader/website_reader.py +0 -175
- agno/document/reader/youtube_reader.py +0 -50
- agno/embedder/__init__.py +0 -1
- agno/embedder/azure_openai.py +0 -86
- agno/embedder/cohere.py +0 -72
- agno/embedder/fastembed.py +0 -37
- agno/embedder/google.py +0 -73
- agno/embedder/huggingface.py +0 -54
- agno/embedder/mistral.py +0 -80
- agno/embedder/ollama.py +0 -57
- agno/embedder/openai.py +0 -74
- agno/embedder/sentence_transformer.py +0 -38
- agno/embedder/voyageai.py +0 -64
- agno/eval/perf.py +0 -201
- agno/file/__init__.py +0 -1
- agno/file/file.py +0 -16
- agno/file/local/csv.py +0 -32
- agno/file/local/txt.py +0 -19
- agno/infra/app.py +0 -240
- agno/infra/base.py +0 -144
- agno/infra/context.py +0 -20
- agno/infra/db_app.py +0 -52
- agno/infra/resource.py +0 -205
- agno/infra/resources.py +0 -55
- agno/knowledge/agent.py +0 -230
- agno/knowledge/arxiv.py +0 -22
- agno/knowledge/combined.py +0 -22
- agno/knowledge/csv.py +0 -28
- agno/knowledge/csv_url.py +0 -19
- agno/knowledge/document.py +0 -20
- agno/knowledge/docx.py +0 -30
- agno/knowledge/json.py +0 -28
- agno/knowledge/langchain.py +0 -71
- agno/knowledge/llamaindex.py +0 -66
- agno/knowledge/pdf.py +0 -28
- agno/knowledge/pdf_url.py +0 -26
- agno/knowledge/s3/base.py +0 -60
- agno/knowledge/s3/pdf.py +0 -21
- agno/knowledge/s3/text.py +0 -23
- agno/knowledge/text.py +0 -30
- agno/knowledge/website.py +0 -88
- agno/knowledge/wikipedia.py +0 -31
- agno/knowledge/youtube.py +0 -22
- agno/memory/agent.py +0 -392
- agno/memory/classifier.py +0 -104
- agno/memory/db/__init__.py +0 -1
- agno/memory/db/base.py +0 -42
- agno/memory/db/mongodb.py +0 -189
- agno/memory/db/postgres.py +0 -203
- agno/memory/db/sqlite.py +0 -193
- agno/memory/memory.py +0 -15
- agno/memory/row.py +0 -36
- agno/memory/summarizer.py +0 -192
- agno/memory/summary.py +0 -19
- agno/memory/workflow.py +0 -38
- agno/models/google/gemini_openai.py +0 -26
- agno/models/ollama/hermes.py +0 -221
- agno/models/ollama/tools.py +0 -362
- agno/models/vertexai/gemini.py +0 -595
- agno/playground/__init__.py +0 -3
- agno/playground/async_router.py +0 -421
- agno/playground/deploy.py +0 -249
- agno/playground/operator.py +0 -92
- agno/playground/playground.py +0 -91
- agno/playground/schemas.py +0 -76
- agno/playground/serve.py +0 -55
- agno/playground/sync_router.py +0 -405
- agno/reasoning/agent.py +0 -68
- agno/run/response.py +0 -112
- agno/storage/agent/__init__.py +0 -0
- agno/storage/agent/base.py +0 -38
- agno/storage/agent/dynamodb.py +0 -350
- agno/storage/agent/json.py +0 -92
- agno/storage/agent/mongodb.py +0 -228
- agno/storage/agent/postgres.py +0 -367
- agno/storage/agent/session.py +0 -79
- agno/storage/agent/singlestore.py +0 -303
- agno/storage/agent/sqlite.py +0 -357
- agno/storage/agent/yaml.py +0 -93
- agno/storage/workflow/__init__.py +0 -0
- agno/storage/workflow/base.py +0 -40
- agno/storage/workflow/mongodb.py +0 -233
- agno/storage/workflow/postgres.py +0 -366
- agno/storage/workflow/session.py +0 -60
- agno/storage/workflow/sqlite.py +0 -359
- agno/tools/googlesearch.py +0 -88
- agno/utils/defaults.py +0 -57
- agno/utils/filesystem.py +0 -39
- agno/utils/git.py +0 -52
- agno/utils/json_io.py +0 -30
- agno/utils/load_env.py +0 -19
- agno/utils/py_io.py +0 -19
- agno/utils/pyproject.py +0 -18
- agno/utils/resource_filter.py +0 -31
- agno/vectordb/singlestore/s2vectordb.py +0 -390
- agno/vectordb/singlestore/s2vectordb2.py +0 -355
- agno/workspace/__init__.py +0 -0
- agno/workspace/config.py +0 -325
- agno/workspace/enums.py +0 -6
- agno/workspace/helpers.py +0 -48
- agno/workspace/operator.py +0 -758
- agno/workspace/settings.py +0 -63
- agno-0.1.2.dist-info/LICENSE +0 -375
- agno-0.1.2.dist-info/METADATA +0 -502
- agno-0.1.2.dist-info/RECORD +0 -352
- agno-0.1.2.dist-info/entry_points.txt +0 -3
- /agno/{cli → db/migrations}/__init__.py +0 -0
- /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
- /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
- /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
- /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
- /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
- /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
- /agno/{reranker → utils/models}/__init__.py +0 -0
- /agno/{storage → utils/print_response}/__init__.py +0 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
agno/tools/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}"
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from os import getenv
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
from agno.tools import Toolkit
|
|
6
|
+
from agno.utils.log import log_debug, logger
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from browserbase import Browserbase
|
|
10
|
+
except ImportError:
|
|
11
|
+
raise ImportError("`browserbase` not installed. Please install using `pip install browserbase`")
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
from playwright.sync_api import sync_playwright
|
|
15
|
+
except ImportError:
|
|
16
|
+
raise ImportError(
|
|
17
|
+
"`playwright` not installed. Please install using `pip install playwright` and run `playwright install`"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class BrowserbaseTools(Toolkit):
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
api_key: Optional[str] = None,
|
|
25
|
+
project_id: Optional[str] = None,
|
|
26
|
+
base_url: Optional[str] = None,
|
|
27
|
+
enable_navigate_to: bool = True,
|
|
28
|
+
enable_screenshot: bool = True,
|
|
29
|
+
enable_get_page_content: bool = True,
|
|
30
|
+
enable_close_session: bool = True,
|
|
31
|
+
all: bool = False,
|
|
32
|
+
**kwargs,
|
|
33
|
+
):
|
|
34
|
+
"""Initialize BrowserbaseTools.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
api_key (str, optional): Browserbase API key.
|
|
38
|
+
project_id (str, optional): Browserbase project ID.
|
|
39
|
+
base_url (str, optional): Custom Browserbase API endpoint URL (NOT the target website URL). Only use this if you're using a self-hosted Browserbase instance or need to connect to a different region.
|
|
40
|
+
"""
|
|
41
|
+
self.api_key = api_key or getenv("BROWSERBASE_API_KEY")
|
|
42
|
+
if not self.api_key:
|
|
43
|
+
raise ValueError(
|
|
44
|
+
"BROWSERBASE_API_KEY is required. Please set the BROWSERBASE_API_KEY environment variable."
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
self.project_id = project_id or getenv("BROWSERBASE_PROJECT_ID")
|
|
48
|
+
if not self.project_id:
|
|
49
|
+
raise ValueError(
|
|
50
|
+
"BROWSERBASE_PROJECT_ID is required. Please set the BROWSERBASE_PROJECT_ID environment variable."
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
self.base_url = base_url or getenv("BROWSERBASE_BASE_URL")
|
|
54
|
+
|
|
55
|
+
# Initialize the Browserbase client with optional base_url
|
|
56
|
+
if self.base_url:
|
|
57
|
+
self.app = Browserbase(api_key=self.api_key, base_url=self.base_url)
|
|
58
|
+
log_debug(f"Using custom Browserbase API endpoint: {self.base_url}")
|
|
59
|
+
else:
|
|
60
|
+
self.app = Browserbase(api_key=self.api_key)
|
|
61
|
+
|
|
62
|
+
self._playwright = None
|
|
63
|
+
self._browser = None
|
|
64
|
+
self._page = None
|
|
65
|
+
self._session = None
|
|
66
|
+
self._connect_url = None
|
|
67
|
+
|
|
68
|
+
tools: List[Any] = []
|
|
69
|
+
if all or enable_navigate_to:
|
|
70
|
+
tools.append(self.navigate_to)
|
|
71
|
+
if all or enable_screenshot:
|
|
72
|
+
tools.append(self.screenshot)
|
|
73
|
+
if all or enable_get_page_content:
|
|
74
|
+
tools.append(self.get_page_content)
|
|
75
|
+
if all or enable_close_session:
|
|
76
|
+
tools.append(self.close_session)
|
|
77
|
+
|
|
78
|
+
super().__init__(name="browserbase_tools", tools=tools, **kwargs)
|
|
79
|
+
|
|
80
|
+
def _ensure_session(self):
|
|
81
|
+
"""Ensures a session exists, creating one if needed."""
|
|
82
|
+
if not self._session:
|
|
83
|
+
try:
|
|
84
|
+
self._session = self.app.sessions.create(project_id=self.project_id) # type: ignore
|
|
85
|
+
self._connect_url = self._session.connect_url if self._session else "" # type: ignore
|
|
86
|
+
if self._session:
|
|
87
|
+
log_debug(f"Created new session with ID: {self._session.id}")
|
|
88
|
+
except Exception as e:
|
|
89
|
+
logger.error(f"Failed to create session: {str(e)}")
|
|
90
|
+
raise
|
|
91
|
+
|
|
92
|
+
def _initialize_browser(self, connect_url: Optional[str] = None):
|
|
93
|
+
"""
|
|
94
|
+
Initialize browser connection if not already initialized.
|
|
95
|
+
Use provided connect_url or ensure we have a session with a connect_url
|
|
96
|
+
"""
|
|
97
|
+
if connect_url:
|
|
98
|
+
self._connect_url = connect_url if connect_url else "" # type: ignore
|
|
99
|
+
elif not self._connect_url:
|
|
100
|
+
self._ensure_session()
|
|
101
|
+
|
|
102
|
+
if not self._playwright:
|
|
103
|
+
self._playwright = sync_playwright().start() # type: ignore
|
|
104
|
+
if self._playwright:
|
|
105
|
+
self._browser = self._playwright.chromium.connect_over_cdp(self._connect_url)
|
|
106
|
+
context = self._browser.contexts[0] if self._browser else ""
|
|
107
|
+
self._page = context.pages[0] or context.new_page() # type: ignore
|
|
108
|
+
|
|
109
|
+
def _cleanup(self):
|
|
110
|
+
"""Clean up browser resources."""
|
|
111
|
+
if self._browser:
|
|
112
|
+
self._browser.close()
|
|
113
|
+
self._browser = None
|
|
114
|
+
if self._playwright:
|
|
115
|
+
self._playwright.stop()
|
|
116
|
+
self._playwright = None
|
|
117
|
+
self._page = None
|
|
118
|
+
|
|
119
|
+
def _create_session(self) -> Dict[str, str]:
|
|
120
|
+
"""Creates a new browser session.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Dictionary containing session details including session_id and connect_url.
|
|
124
|
+
"""
|
|
125
|
+
self._ensure_session()
|
|
126
|
+
return {
|
|
127
|
+
"session_id": self._session.id if self._session else "",
|
|
128
|
+
"connect_url": self._session.connect_url if self._session else "",
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
def navigate_to(self, url: str, connect_url: Optional[str] = None) -> str:
|
|
132
|
+
"""Navigates to a URL.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
url (str): The URL to navigate to
|
|
136
|
+
connect_url (str, optional): The connection URL from an existing session
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
JSON string with navigation status
|
|
140
|
+
"""
|
|
141
|
+
try:
|
|
142
|
+
self._initialize_browser(connect_url)
|
|
143
|
+
if self._page:
|
|
144
|
+
self._page.goto(url, wait_until="networkidle")
|
|
145
|
+
result = {"status": "complete", "title": self._page.title() if self._page else "", "url": url}
|
|
146
|
+
return json.dumps(result)
|
|
147
|
+
except Exception as e:
|
|
148
|
+
self._cleanup()
|
|
149
|
+
raise e
|
|
150
|
+
|
|
151
|
+
def screenshot(self, path: str, full_page: bool = True, connect_url: Optional[str] = None) -> str:
|
|
152
|
+
"""Takes a screenshot of the current page.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
path (str): Where to save the screenshot
|
|
156
|
+
full_page (bool): Whether to capture the full page
|
|
157
|
+
connect_url (str, optional): The connection URL from an existing session
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
JSON string confirming screenshot was saved
|
|
161
|
+
"""
|
|
162
|
+
try:
|
|
163
|
+
self._initialize_browser(connect_url)
|
|
164
|
+
if self._page:
|
|
165
|
+
self._page.screenshot(path=path, full_page=full_page)
|
|
166
|
+
return json.dumps({"status": "success", "path": path})
|
|
167
|
+
except Exception as e:
|
|
168
|
+
self._cleanup()
|
|
169
|
+
raise e
|
|
170
|
+
|
|
171
|
+
def get_page_content(self, connect_url: Optional[str] = None) -> str:
|
|
172
|
+
"""Gets the HTML content of the current page.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
connect_url (str, optional): The connection URL from an existing session
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
The page HTML content
|
|
179
|
+
"""
|
|
180
|
+
try:
|
|
181
|
+
self._initialize_browser(connect_url)
|
|
182
|
+
return self._page.content() if self._page else ""
|
|
183
|
+
except Exception as e:
|
|
184
|
+
self._cleanup()
|
|
185
|
+
raise e
|
|
186
|
+
|
|
187
|
+
def close_session(self) -> str:
|
|
188
|
+
"""Closes a browser session.
|
|
189
|
+
Args:
|
|
190
|
+
session_id (str, optional): The session ID to close. If not provided, will use the current session.
|
|
191
|
+
Returns:
|
|
192
|
+
JSON string with closure status
|
|
193
|
+
"""
|
|
194
|
+
try:
|
|
195
|
+
# First cleanup our local browser resources
|
|
196
|
+
self._cleanup()
|
|
197
|
+
|
|
198
|
+
# Reset session state
|
|
199
|
+
self._session = None
|
|
200
|
+
self._connect_url = None
|
|
201
|
+
|
|
202
|
+
return json.dumps(
|
|
203
|
+
{
|
|
204
|
+
"status": "closed",
|
|
205
|
+
"message": "Browser resources cleaned up. Session will auto-close if not already closed.",
|
|
206
|
+
}
|
|
207
|
+
)
|
|
208
|
+
except Exception as e:
|
|
209
|
+
return json.dumps({"status": "warning", "message": f"Cleanup completed with warning: {str(e)}"})
|
agno/tools/calcom.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
from os import getenv
|
|
3
|
-
from typing import Dict, Optional
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
4
|
|
|
5
5
|
from agno.tools import Toolkit
|
|
6
6
|
from agno.utils.log import logger
|
|
@@ -18,11 +18,14 @@ class CalComTools(Toolkit):
|
|
|
18
18
|
api_key: Optional[str] = None,
|
|
19
19
|
event_type_id: Optional[int] = None,
|
|
20
20
|
user_timezone: Optional[str] = None,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
# Enable flags for <6 functions
|
|
22
|
+
enable_get_available_slots: bool = True,
|
|
23
|
+
enable_create_booking: bool = True,
|
|
24
|
+
enable_get_upcoming_bookings: bool = True,
|
|
25
|
+
enable_reschedule_booking: bool = True,
|
|
26
|
+
enable_cancel_booking: bool = True,
|
|
27
|
+
all: bool = False,
|
|
28
|
+
**kwargs,
|
|
26
29
|
):
|
|
27
30
|
"""Initialize the Cal.com toolkit.
|
|
28
31
|
|
|
@@ -31,12 +34,14 @@ class CalComTools(Toolkit):
|
|
|
31
34
|
event_type_id: Default event type ID for bookings
|
|
32
35
|
user_timezone: User's timezone in IANA format (e.g., 'Asia/Kolkata')
|
|
33
36
|
"""
|
|
34
|
-
super().__init__(name="calcom")
|
|
35
37
|
|
|
36
38
|
# Get credentials from environment if not provided
|
|
37
39
|
self.api_key = api_key or getenv("CALCOM_API_KEY")
|
|
38
40
|
event_type_str = getenv("CALCOM_EVENT_TYPE_ID")
|
|
39
|
-
|
|
41
|
+
if event_type_id is not None:
|
|
42
|
+
self.event_type_id = int(event_type_id)
|
|
43
|
+
else:
|
|
44
|
+
self.event_type_id = int(event_type_str) if event_type_str is not None else 0
|
|
40
45
|
|
|
41
46
|
if not self.api_key:
|
|
42
47
|
logger.error("CALCOM_API_KEY not set. Please set the CALCOM_API_KEY environment variable.")
|
|
@@ -45,17 +50,19 @@ class CalComTools(Toolkit):
|
|
|
45
50
|
|
|
46
51
|
self.user_timezone = user_timezone or "America/New_York"
|
|
47
52
|
|
|
48
|
-
|
|
49
|
-
if
|
|
50
|
-
|
|
51
|
-
if
|
|
52
|
-
|
|
53
|
-
if
|
|
54
|
-
|
|
55
|
-
if
|
|
56
|
-
|
|
57
|
-
if
|
|
58
|
-
|
|
53
|
+
tools: List[Any] = []
|
|
54
|
+
if all or enable_get_available_slots:
|
|
55
|
+
tools.append(self.get_available_slots)
|
|
56
|
+
if all or enable_create_booking:
|
|
57
|
+
tools.append(self.create_booking)
|
|
58
|
+
if all or enable_get_upcoming_bookings:
|
|
59
|
+
tools.append(self.get_upcoming_bookings)
|
|
60
|
+
if all or enable_reschedule_booking:
|
|
61
|
+
tools.append(self.reschedule_booking)
|
|
62
|
+
if all or enable_cancel_booking:
|
|
63
|
+
tools.append(self.cancel_booking)
|
|
64
|
+
|
|
65
|
+
super().__init__(name="calcom", tools=tools, **kwargs)
|
|
59
66
|
|
|
60
67
|
def _convert_to_user_timezone(self, utc_time: str) -> str:
|
|
61
68
|
"""Convert UTC time to user's timezone.
|
|
@@ -111,7 +118,7 @@ class CalComTools(Toolkit):
|
|
|
111
118
|
"eventTypeId": str(self.event_type_id),
|
|
112
119
|
}
|
|
113
120
|
|
|
114
|
-
response = requests.get(url, headers=self._get_headers(), params=querystring)
|
|
121
|
+
response = requests.get(url, headers=self._get_headers(), params=querystring) # type: ignore
|
|
115
122
|
if response.status_code == 200:
|
|
116
123
|
slots = response.json()["data"]["slots"]
|
|
117
124
|
available_slots = []
|
|
@@ -160,18 +167,20 @@ class CalComTools(Toolkit):
|
|
|
160
167
|
logger.error(f"Error creating booking: {e}")
|
|
161
168
|
return f"Error: {str(e)}"
|
|
162
169
|
|
|
163
|
-
def get_upcoming_bookings(self, email: str) -> str:
|
|
170
|
+
def get_upcoming_bookings(self, email: Optional[str] = None) -> str:
|
|
164
171
|
"""Get all upcoming bookings for an attendee.
|
|
165
172
|
|
|
166
173
|
Args:
|
|
167
|
-
email: Attendee's email
|
|
174
|
+
email (str): Attendee's email [Optional]
|
|
168
175
|
|
|
169
176
|
Returns:
|
|
170
177
|
str: List of upcoming bookings or error message
|
|
171
178
|
"""
|
|
172
179
|
try:
|
|
173
180
|
url = "https://api.cal.com/v2/bookings"
|
|
174
|
-
querystring = {"status": "upcoming"
|
|
181
|
+
querystring = {"status": "upcoming"}
|
|
182
|
+
if email:
|
|
183
|
+
querystring["attendeeEmail"] = email
|
|
175
184
|
|
|
176
185
|
response = requests.get(url, headers=self._get_headers(), params=querystring)
|
|
177
186
|
if response.status_code == 200:
|