agno 2.2.13__py3-none-any.whl → 2.4.3__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/agent/__init__.py +6 -0
- agno/agent/agent.py +5252 -3145
- agno/agent/remote.py +525 -0
- agno/api/api.py +2 -0
- agno/client/__init__.py +3 -0
- agno/client/a2a/__init__.py +10 -0
- agno/client/a2a/client.py +554 -0
- agno/client/a2a/schemas.py +112 -0
- agno/client/a2a/utils.py +369 -0
- agno/client/os.py +2669 -0
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/manager.py +2 -2
- agno/db/base.py +927 -6
- agno/db/dynamo/dynamo.py +788 -2
- agno/db/dynamo/schemas.py +128 -0
- agno/db/dynamo/utils.py +26 -3
- agno/db/firestore/firestore.py +674 -50
- agno/db/firestore/schemas.py +41 -0
- agno/db/firestore/utils.py +25 -10
- agno/db/gcs_json/gcs_json_db.py +506 -3
- agno/db/gcs_json/utils.py +14 -2
- agno/db/in_memory/in_memory_db.py +203 -4
- agno/db/in_memory/utils.py +14 -2
- agno/db/json/json_db.py +498 -2
- agno/db/json/utils.py +14 -2
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/utils.py +19 -0
- agno/db/migrations/v1_to_v2.py +54 -16
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +977 -0
- agno/db/mongo/async_mongo.py +1013 -39
- agno/db/mongo/mongo.py +684 -4
- agno/db/mongo/schemas.py +48 -0
- agno/db/mongo/utils.py +17 -0
- agno/db/mysql/__init__.py +2 -1
- agno/db/mysql/async_mysql.py +2958 -0
- agno/db/mysql/mysql.py +722 -53
- agno/db/mysql/schemas.py +77 -11
- agno/db/mysql/utils.py +151 -8
- agno/db/postgres/async_postgres.py +1254 -137
- agno/db/postgres/postgres.py +2316 -93
- agno/db/postgres/schemas.py +153 -21
- agno/db/postgres/utils.py +22 -7
- agno/db/redis/redis.py +531 -3
- agno/db/redis/schemas.py +36 -0
- agno/db/redis/utils.py +31 -15
- agno/db/schemas/evals.py +1 -0
- agno/db/schemas/memory.py +20 -9
- agno/db/singlestore/schemas.py +70 -1
- agno/db/singlestore/singlestore.py +737 -74
- agno/db/singlestore/utils.py +13 -3
- agno/db/sqlite/async_sqlite.py +1069 -89
- agno/db/sqlite/schemas.py +133 -1
- agno/db/sqlite/sqlite.py +2203 -165
- agno/db/sqlite/utils.py +21 -11
- agno/db/surrealdb/models.py +25 -0
- agno/db/surrealdb/surrealdb.py +603 -1
- agno/db/utils.py +60 -0
- agno/eval/__init__.py +26 -3
- agno/eval/accuracy.py +25 -12
- agno/eval/agent_as_judge.py +871 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +10 -4
- agno/eval/reliability.py +22 -13
- agno/eval/utils.py +2 -1
- agno/exceptions.py +42 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/client.py +13 -2
- agno/knowledge/__init__.py +4 -0
- agno/knowledge/chunking/code.py +90 -0
- agno/knowledge/chunking/document.py +65 -4
- agno/knowledge/chunking/fixed.py +4 -1
- agno/knowledge/chunking/markdown.py +102 -11
- agno/knowledge/chunking/recursive.py +2 -2
- agno/knowledge/chunking/semantic.py +130 -48
- agno/knowledge/chunking/strategy.py +18 -0
- agno/knowledge/embedder/azure_openai.py +0 -1
- agno/knowledge/embedder/google.py +1 -1
- agno/knowledge/embedder/mistral.py +1 -1
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/openai.py +16 -12
- agno/knowledge/filesystem.py +412 -0
- agno/knowledge/knowledge.py +4261 -1199
- agno/knowledge/protocol.py +134 -0
- agno/knowledge/reader/arxiv_reader.py +3 -2
- agno/knowledge/reader/base.py +9 -7
- agno/knowledge/reader/csv_reader.py +91 -42
- agno/knowledge/reader/docx_reader.py +9 -10
- agno/knowledge/reader/excel_reader.py +225 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +38 -48
- agno/knowledge/reader/firecrawl_reader.py +3 -2
- agno/knowledge/reader/json_reader.py +16 -22
- agno/knowledge/reader/markdown_reader.py +15 -14
- agno/knowledge/reader/pdf_reader.py +33 -28
- agno/knowledge/reader/pptx_reader.py +9 -10
- agno/knowledge/reader/reader_factory.py +135 -1
- agno/knowledge/reader/s3_reader.py +8 -16
- agno/knowledge/reader/tavily_reader.py +3 -3
- agno/knowledge/reader/text_reader.py +15 -14
- agno/knowledge/reader/utils/__init__.py +17 -0
- agno/knowledge/reader/utils/spreadsheet.py +114 -0
- agno/knowledge/reader/web_search_reader.py +8 -65
- agno/knowledge/reader/website_reader.py +16 -13
- agno/knowledge/reader/wikipedia_reader.py +36 -3
- agno/knowledge/reader/youtube_reader.py +3 -2
- agno/knowledge/remote_content/__init__.py +33 -0
- agno/knowledge/remote_content/config.py +266 -0
- agno/knowledge/remote_content/remote_content.py +105 -17
- agno/knowledge/utils.py +76 -22
- agno/learn/__init__.py +71 -0
- agno/learn/config.py +463 -0
- agno/learn/curate.py +185 -0
- agno/learn/machine.py +725 -0
- agno/learn/schemas.py +1114 -0
- agno/learn/stores/__init__.py +38 -0
- agno/learn/stores/decision_log.py +1156 -0
- agno/learn/stores/entity_memory.py +3275 -0
- agno/learn/stores/learned_knowledge.py +1583 -0
- agno/learn/stores/protocol.py +117 -0
- agno/learn/stores/session_context.py +1217 -0
- agno/learn/stores/user_memory.py +1495 -0
- agno/learn/stores/user_profile.py +1220 -0
- agno/learn/utils.py +209 -0
- agno/media.py +22 -6
- agno/memory/__init__.py +14 -1
- agno/memory/manager.py +223 -8
- 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/aimlapi.py +17 -0
- agno/models/anthropic/claude.py +434 -59
- agno/models/aws/bedrock.py +121 -20
- agno/models/aws/claude.py +131 -274
- agno/models/azure/ai_foundry.py +10 -6
- agno/models/azure/openai_chat.py +33 -10
- agno/models/base.py +1162 -561
- agno/models/cerebras/cerebras.py +120 -24
- agno/models/cerebras/cerebras_openai.py +21 -2
- agno/models/cohere/chat.py +65 -6
- agno/models/cometapi/cometapi.py +18 -1
- agno/models/dashscope/dashscope.py +2 -3
- agno/models/deepinfra/deepinfra.py +18 -1
- agno/models/deepseek/deepseek.py +69 -3
- agno/models/fireworks/fireworks.py +18 -1
- agno/models/google/gemini.py +959 -89
- agno/models/google/utils.py +22 -0
- agno/models/groq/groq.py +48 -18
- agno/models/huggingface/huggingface.py +17 -6
- agno/models/ibm/watsonx.py +16 -6
- agno/models/internlm/internlm.py +18 -1
- agno/models/langdb/langdb.py +13 -1
- agno/models/litellm/chat.py +88 -9
- agno/models/litellm/litellm_openai.py +18 -1
- agno/models/message.py +24 -5
- agno/models/meta/llama.py +40 -13
- agno/models/meta/llama_openai.py +22 -21
- agno/models/metrics.py +12 -0
- agno/models/mistral/mistral.py +8 -4
- agno/models/n1n/__init__.py +3 -0
- agno/models/n1n/n1n.py +57 -0
- agno/models/nebius/nebius.py +6 -7
- agno/models/nvidia/nvidia.py +20 -3
- agno/models/ollama/__init__.py +2 -0
- agno/models/ollama/chat.py +17 -6
- agno/models/ollama/responses.py +100 -0
- agno/models/openai/__init__.py +2 -0
- agno/models/openai/chat.py +117 -26
- agno/models/openai/open_responses.py +46 -0
- agno/models/openai/responses.py +110 -32
- agno/models/openrouter/__init__.py +2 -0
- agno/models/openrouter/openrouter.py +67 -2
- agno/models/openrouter/responses.py +146 -0
- agno/models/perplexity/perplexity.py +19 -1
- agno/models/portkey/portkey.py +7 -6
- agno/models/requesty/requesty.py +19 -2
- agno/models/response.py +20 -2
- agno/models/sambanova/sambanova.py +20 -3
- agno/models/siliconflow/siliconflow.py +19 -2
- agno/models/together/together.py +20 -3
- agno/models/vercel/v0.py +20 -3
- agno/models/vertexai/claude.py +124 -4
- agno/models/vllm/vllm.py +19 -14
- agno/models/xai/xai.py +19 -2
- agno/os/app.py +467 -137
- agno/os/auth.py +253 -5
- agno/os/config.py +22 -0
- agno/os/interfaces/a2a/a2a.py +7 -6
- agno/os/interfaces/a2a/router.py +635 -26
- agno/os/interfaces/a2a/utils.py +32 -33
- agno/os/interfaces/agui/agui.py +5 -3
- agno/os/interfaces/agui/router.py +26 -16
- agno/os/interfaces/agui/utils.py +97 -57
- agno/os/interfaces/base.py +7 -7
- agno/os/interfaces/slack/router.py +16 -7
- agno/os/interfaces/slack/slack.py +7 -7
- agno/os/interfaces/whatsapp/router.py +35 -7
- agno/os/interfaces/whatsapp/security.py +3 -1
- agno/os/interfaces/whatsapp/whatsapp.py +11 -8
- agno/os/managers.py +326 -0
- agno/os/mcp.py +652 -79
- agno/os/middleware/__init__.py +4 -0
- agno/os/middleware/jwt.py +718 -115
- agno/os/middleware/trailing_slash.py +27 -0
- agno/os/router.py +105 -1558
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +655 -0
- agno/os/routers/agents/schema.py +288 -0
- agno/os/routers/components/__init__.py +3 -0
- agno/os/routers/components/components.py +475 -0
- agno/os/routers/database.py +155 -0
- agno/os/routers/evals/evals.py +111 -18
- agno/os/routers/evals/schemas.py +38 -5
- agno/os/routers/evals/utils.py +80 -11
- agno/os/routers/health.py +3 -3
- agno/os/routers/knowledge/knowledge.py +284 -35
- agno/os/routers/knowledge/schemas.py +14 -2
- agno/os/routers/memory/memory.py +274 -11
- agno/os/routers/memory/schemas.py +44 -3
- agno/os/routers/metrics/metrics.py +30 -15
- agno/os/routers/metrics/schemas.py +10 -6
- agno/os/routers/registry/__init__.py +3 -0
- agno/os/routers/registry/registry.py +337 -0
- agno/os/routers/session/session.py +143 -14
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +550 -0
- agno/os/routers/teams/schema.py +280 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +549 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +757 -0
- agno/os/routers/workflows/schema.py +139 -0
- agno/os/schema.py +157 -584
- agno/os/scopes.py +469 -0
- agno/os/settings.py +3 -0
- agno/os/utils.py +574 -185
- agno/reasoning/anthropic.py +85 -1
- agno/reasoning/azure_ai_foundry.py +93 -1
- agno/reasoning/deepseek.py +102 -2
- agno/reasoning/default.py +6 -7
- agno/reasoning/gemini.py +87 -3
- agno/reasoning/groq.py +109 -2
- agno/reasoning/helpers.py +6 -7
- agno/reasoning/manager.py +1238 -0
- agno/reasoning/ollama.py +93 -1
- agno/reasoning/openai.py +115 -1
- agno/reasoning/vertexai.py +85 -1
- agno/registry/__init__.py +3 -0
- agno/registry/registry.py +68 -0
- agno/remote/__init__.py +3 -0
- agno/remote/base.py +581 -0
- agno/run/__init__.py +2 -4
- agno/run/agent.py +134 -19
- agno/run/base.py +49 -1
- agno/run/cancel.py +65 -52
- agno/run/cancellation_management/__init__.py +9 -0
- agno/run/cancellation_management/base.py +78 -0
- agno/run/cancellation_management/in_memory_cancellation_manager.py +100 -0
- agno/run/cancellation_management/redis_cancellation_manager.py +236 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +111 -19
- agno/run/workflow.py +2 -1
- agno/session/agent.py +57 -92
- agno/session/summary.py +1 -1
- agno/session/team.py +62 -115
- agno/session/workflow.py +353 -57
- agno/skills/__init__.py +17 -0
- agno/skills/agent_skills.py +377 -0
- agno/skills/errors.py +32 -0
- agno/skills/loaders/__init__.py +4 -0
- agno/skills/loaders/base.py +27 -0
- agno/skills/loaders/local.py +216 -0
- agno/skills/skill.py +65 -0
- agno/skills/utils.py +107 -0
- agno/skills/validator.py +277 -0
- agno/table.py +10 -0
- agno/team/__init__.py +5 -1
- agno/team/remote.py +447 -0
- agno/team/team.py +3769 -2202
- agno/tools/brandfetch.py +27 -18
- agno/tools/browserbase.py +225 -16
- agno/tools/crawl4ai.py +3 -0
- agno/tools/duckduckgo.py +25 -71
- agno/tools/exa.py +0 -21
- agno/tools/file.py +14 -13
- agno/tools/file_generation.py +12 -6
- agno/tools/firecrawl.py +15 -7
- agno/tools/function.py +94 -113
- agno/tools/google_bigquery.py +11 -2
- agno/tools/google_drive.py +4 -3
- agno/tools/knowledge.py +9 -4
- agno/tools/mcp/mcp.py +301 -18
- agno/tools/mcp/multi_mcp.py +269 -14
- agno/tools/mem0.py +11 -10
- agno/tools/memory.py +47 -46
- agno/tools/mlx_transcribe.py +10 -7
- agno/tools/models/nebius.py +5 -5
- agno/tools/models_labs.py +20 -10
- agno/tools/nano_banana.py +151 -0
- agno/tools/parallel.py +0 -7
- agno/tools/postgres.py +76 -36
- agno/tools/python.py +14 -6
- agno/tools/reasoning.py +30 -23
- agno/tools/redshift.py +406 -0
- agno/tools/shopify.py +1519 -0
- agno/tools/spotify.py +919 -0
- agno/tools/tavily.py +4 -1
- agno/tools/toolkit.py +253 -18
- agno/tools/websearch.py +93 -0
- agno/tools/website.py +1 -1
- agno/tools/wikipedia.py +1 -1
- agno/tools/workflow.py +56 -48
- agno/tools/yfinance.py +12 -11
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +161 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +112 -0
- agno/utils/agent.py +251 -10
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +264 -7
- agno/utils/hooks.py +111 -3
- agno/utils/http.py +161 -2
- agno/utils/mcp.py +49 -8
- agno/utils/media.py +22 -1
- agno/utils/models/ai_foundry.py +9 -2
- agno/utils/models/claude.py +20 -5
- agno/utils/models/cohere.py +9 -2
- agno/utils/models/llama.py +9 -2
- agno/utils/models/mistral.py +4 -2
- agno/utils/os.py +0 -0
- agno/utils/print_response/agent.py +99 -16
- agno/utils/print_response/team.py +223 -24
- agno/utils/print_response/workflow.py +0 -2
- agno/utils/prompts.py +8 -6
- agno/utils/remote.py +23 -0
- agno/utils/response.py +1 -13
- agno/utils/string.py +91 -2
- agno/utils/team.py +62 -12
- agno/utils/tokens.py +657 -0
- agno/vectordb/base.py +15 -2
- agno/vectordb/cassandra/cassandra.py +1 -1
- agno/vectordb/chroma/__init__.py +2 -1
- agno/vectordb/chroma/chromadb.py +468 -23
- agno/vectordb/clickhouse/clickhousedb.py +1 -1
- agno/vectordb/couchbase/couchbase.py +6 -2
- agno/vectordb/lancedb/lance_db.py +7 -38
- agno/vectordb/lightrag/lightrag.py +7 -6
- agno/vectordb/milvus/milvus.py +118 -84
- agno/vectordb/mongodb/__init__.py +2 -1
- agno/vectordb/mongodb/mongodb.py +14 -31
- agno/vectordb/pgvector/pgvector.py +120 -66
- agno/vectordb/pineconedb/pineconedb.py +2 -19
- agno/vectordb/qdrant/__init__.py +2 -1
- agno/vectordb/qdrant/qdrant.py +33 -56
- agno/vectordb/redis/__init__.py +2 -1
- agno/vectordb/redis/redisdb.py +19 -31
- agno/vectordb/singlestore/singlestore.py +17 -9
- agno/vectordb/surrealdb/surrealdb.py +2 -38
- agno/vectordb/weaviate/__init__.py +2 -1
- agno/vectordb/weaviate/weaviate.py +7 -3
- agno/workflow/__init__.py +5 -1
- agno/workflow/agent.py +2 -2
- agno/workflow/condition.py +12 -10
- agno/workflow/loop.py +28 -9
- agno/workflow/parallel.py +21 -13
- agno/workflow/remote.py +362 -0
- agno/workflow/router.py +12 -9
- agno/workflow/step.py +261 -36
- agno/workflow/steps.py +12 -8
- agno/workflow/types.py +40 -77
- agno/workflow/workflow.py +939 -213
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/METADATA +134 -181
- agno-2.4.3.dist-info/RECORD +677 -0
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/WHEEL +1 -1
- agno/tools/googlesearch.py +0 -98
- agno/tools/memori.py +0 -339
- agno-2.2.13.dist-info/RECORD +0 -575
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/top_level.txt +0 -0
agno/tools/brandfetch.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Brandfetch API toolkit for retrieving brand data and searching brands.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import warnings
|
|
5
6
|
from os import getenv
|
|
6
|
-
from typing import Any, Optional
|
|
7
|
+
from typing import Any, List, Optional
|
|
7
8
|
|
|
8
9
|
try:
|
|
9
10
|
import httpx
|
|
@@ -31,8 +32,6 @@ class BrandfetchTools(Toolkit):
|
|
|
31
32
|
all: bool - if True, will use all tools
|
|
32
33
|
enable_search_by_identifier: bool - if True, will use search by identifier
|
|
33
34
|
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
35
|
"""
|
|
37
36
|
|
|
38
37
|
def __init__(
|
|
@@ -44,9 +43,18 @@ class BrandfetchTools(Toolkit):
|
|
|
44
43
|
enable_search_by_identifier: bool = True,
|
|
45
44
|
enable_search_by_brand: bool = False,
|
|
46
45
|
all: bool = False,
|
|
47
|
-
async_tools: bool = False,
|
|
46
|
+
async_tools: bool = False, # Deprecated
|
|
48
47
|
**kwargs,
|
|
49
48
|
):
|
|
49
|
+
# Handle deprecated async_tools parameter
|
|
50
|
+
if async_tools:
|
|
51
|
+
warnings.warn(
|
|
52
|
+
"The 'async_tools' parameter is deprecated and will be removed in a future version. "
|
|
53
|
+
"Async tools are now automatically used when calling agent.arun() or agent.aprint_response().",
|
|
54
|
+
DeprecationWarning,
|
|
55
|
+
stacklevel=2,
|
|
56
|
+
)
|
|
57
|
+
|
|
50
58
|
self.api_key = api_key or getenv("BRANDFETCH_API_KEY")
|
|
51
59
|
self.client_id = client_id or getenv("BRANDFETCH_CLIENT_ID")
|
|
52
60
|
self.base_url = base_url
|
|
@@ -54,20 +62,21 @@ class BrandfetchTools(Toolkit):
|
|
|
54
62
|
self.search_url = f"{self.base_url}/search"
|
|
55
63
|
self.brand_url = f"{self.base_url}/brands"
|
|
56
64
|
|
|
57
|
-
|
|
58
|
-
#
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
# Build tools lists
|
|
66
|
+
# sync tools: used by agent.run() and agent.print_response()
|
|
67
|
+
# async tools: used by agent.arun() and agent.aprint_response()
|
|
68
|
+
tools: List[Any] = []
|
|
69
|
+
async_tools_list: List[tuple] = []
|
|
70
|
+
|
|
71
|
+
if all or enable_search_by_identifier:
|
|
72
|
+
tools.append(self.search_by_identifier)
|
|
73
|
+
async_tools_list.append((self.asearch_by_identifier, "search_by_identifier"))
|
|
74
|
+
if all or enable_search_by_brand:
|
|
75
|
+
tools.append(self.search_by_brand)
|
|
76
|
+
async_tools_list.append((self.asearch_by_brand, "search_by_brand"))
|
|
77
|
+
|
|
69
78
|
name = kwargs.pop("name", "brandfetch_tools")
|
|
70
|
-
super().__init__(name=name, tools=tools, **kwargs)
|
|
79
|
+
super().__init__(name=name, tools=tools, async_tools=async_tools_list, **kwargs)
|
|
71
80
|
|
|
72
81
|
async def asearch_by_identifier(self, identifier: str) -> dict[str, Any]:
|
|
73
82
|
"""
|
agno/tools/browserbase.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import re
|
|
2
3
|
from os import getenv
|
|
3
4
|
from typing import Any, Dict, List, Optional
|
|
4
5
|
|
|
@@ -10,13 +11,6 @@ try:
|
|
|
10
11
|
except ImportError:
|
|
11
12
|
raise ImportError("`browserbase` not installed. Please install using `pip install browserbase`")
|
|
12
13
|
|
|
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
14
|
|
|
21
15
|
class BrowserbaseTools(Toolkit):
|
|
22
16
|
def __init__(
|
|
@@ -29,6 +23,8 @@ class BrowserbaseTools(Toolkit):
|
|
|
29
23
|
enable_get_page_content: bool = True,
|
|
30
24
|
enable_close_session: bool = True,
|
|
31
25
|
all: bool = False,
|
|
26
|
+
parse_html: bool = True,
|
|
27
|
+
max_content_length: Optional[int] = 100000,
|
|
32
28
|
**kwargs,
|
|
33
29
|
):
|
|
34
30
|
"""Initialize BrowserbaseTools.
|
|
@@ -36,8 +32,21 @@ class BrowserbaseTools(Toolkit):
|
|
|
36
32
|
Args:
|
|
37
33
|
api_key (str, optional): Browserbase API key.
|
|
38
34
|
project_id (str, optional): Browserbase project ID.
|
|
39
|
-
base_url (str, optional): Custom Browserbase API endpoint URL (NOT the target website URL).
|
|
35
|
+
base_url (str, optional): Custom Browserbase API endpoint URL (NOT the target website URL).
|
|
36
|
+
Only use this if you're using a self-hosted Browserbase instance or need to connect to a different region.
|
|
37
|
+
enable_navigate_to (bool): Enable the navigate_to tool. Defaults to True.
|
|
38
|
+
enable_screenshot (bool): Enable the screenshot tool. Defaults to True.
|
|
39
|
+
enable_get_page_content (bool): Enable the get_page_content tool. Defaults to True.
|
|
40
|
+
enable_close_session (bool): Enable the close_session tool. Defaults to True.
|
|
41
|
+
all (bool): Enable all tools. Defaults to False.
|
|
42
|
+
parse_html (bool): If True, extract only visible text content instead of raw HTML. Defaults to True.
|
|
43
|
+
This significantly reduces token usage and is recommended for most use cases.
|
|
44
|
+
max_content_length (int, optional): Maximum character length for page content. Defaults to 100000.
|
|
45
|
+
Content exceeding this limit will be truncated with a notice. Set to None for no limit.
|
|
40
46
|
"""
|
|
47
|
+
self.parse_html = parse_html
|
|
48
|
+
self.max_content_length = max_content_length
|
|
49
|
+
|
|
41
50
|
self.api_key = api_key or getenv("BROWSERBASE_API_KEY")
|
|
42
51
|
if not self.api_key:
|
|
43
52
|
raise ValueError(
|
|
@@ -59,23 +68,40 @@ class BrowserbaseTools(Toolkit):
|
|
|
59
68
|
else:
|
|
60
69
|
self.app = Browserbase(api_key=self.api_key)
|
|
61
70
|
|
|
71
|
+
# Sync playwright state
|
|
62
72
|
self._playwright = None
|
|
63
73
|
self._browser = None
|
|
64
74
|
self._page = None
|
|
75
|
+
|
|
76
|
+
# Async playwright state
|
|
77
|
+
self._async_playwright = None
|
|
78
|
+
self._async_browser = None
|
|
79
|
+
self._async_page = None
|
|
80
|
+
|
|
81
|
+
# Shared session state
|
|
65
82
|
self._session = None
|
|
66
83
|
self._connect_url = None
|
|
67
84
|
|
|
85
|
+
# Build tools lists
|
|
86
|
+
# sync tools: used by agent.run() and agent.print_response()
|
|
87
|
+
# async tools: used by agent.arun() and agent.aprint_response()
|
|
68
88
|
tools: List[Any] = []
|
|
89
|
+
async_tools: List[tuple] = []
|
|
90
|
+
|
|
69
91
|
if all or enable_navigate_to:
|
|
70
92
|
tools.append(self.navigate_to)
|
|
93
|
+
async_tools.append((self.anavigate_to, "navigate_to"))
|
|
71
94
|
if all or enable_screenshot:
|
|
72
95
|
tools.append(self.screenshot)
|
|
96
|
+
async_tools.append((self.ascreenshot, "screenshot"))
|
|
73
97
|
if all or enable_get_page_content:
|
|
74
98
|
tools.append(self.get_page_content)
|
|
99
|
+
async_tools.append((self.aget_page_content, "get_page_content"))
|
|
75
100
|
if all or enable_close_session:
|
|
76
101
|
tools.append(self.close_session)
|
|
102
|
+
async_tools.append((self.aclose_session, "close_session"))
|
|
77
103
|
|
|
78
|
-
super().__init__(name="browserbase_tools", tools=tools, **kwargs)
|
|
104
|
+
super().__init__(name="browserbase_tools", tools=tools, async_tools=async_tools, **kwargs)
|
|
79
105
|
|
|
80
106
|
def _ensure_session(self):
|
|
81
107
|
"""Ensures a session exists, creating one if needed."""
|
|
@@ -91,9 +117,16 @@ class BrowserbaseTools(Toolkit):
|
|
|
91
117
|
|
|
92
118
|
def _initialize_browser(self, connect_url: Optional[str] = None):
|
|
93
119
|
"""
|
|
94
|
-
Initialize browser connection if not already initialized.
|
|
120
|
+
Initialize sync browser connection if not already initialized.
|
|
95
121
|
Use provided connect_url or ensure we have a session with a connect_url
|
|
96
122
|
"""
|
|
123
|
+
try:
|
|
124
|
+
from playwright.sync_api import sync_playwright # type: ignore[import-not-found]
|
|
125
|
+
except ImportError:
|
|
126
|
+
raise ImportError(
|
|
127
|
+
"`playwright` not installed. Please install using `pip install playwright` and run `playwright install`"
|
|
128
|
+
)
|
|
129
|
+
|
|
97
130
|
if connect_url:
|
|
98
131
|
self._connect_url = connect_url if connect_url else "" # type: ignore
|
|
99
132
|
elif not self._connect_url:
|
|
@@ -107,7 +140,7 @@ class BrowserbaseTools(Toolkit):
|
|
|
107
140
|
self._page = context.pages[0] or context.new_page() # type: ignore
|
|
108
141
|
|
|
109
142
|
def _cleanup(self):
|
|
110
|
-
"""Clean up browser resources."""
|
|
143
|
+
"""Clean up sync browser resources."""
|
|
111
144
|
if self._browser:
|
|
112
145
|
self._browser.close()
|
|
113
146
|
self._browser = None
|
|
@@ -168,26 +201,77 @@ class BrowserbaseTools(Toolkit):
|
|
|
168
201
|
self._cleanup()
|
|
169
202
|
raise e
|
|
170
203
|
|
|
204
|
+
def _extract_text_content(self, html: str) -> str:
|
|
205
|
+
"""Extract visible text content from HTML, removing scripts, styles, and tags.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
html: Raw HTML content
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Cleaned text content
|
|
212
|
+
"""
|
|
213
|
+
# Remove script and style elements
|
|
214
|
+
html = re.sub(r"<script[^>]*>.*?</script>", "", html, flags=re.DOTALL | re.IGNORECASE)
|
|
215
|
+
html = re.sub(r"<style[^>]*>.*?</style>", "", html, flags=re.DOTALL | re.IGNORECASE)
|
|
216
|
+
# Remove HTML comments
|
|
217
|
+
html = re.sub(r"<!--.*?-->", "", html, flags=re.DOTALL)
|
|
218
|
+
# Remove all HTML tags
|
|
219
|
+
html = re.sub(r"<[^>]+>", " ", html)
|
|
220
|
+
# Decode common HTML entities
|
|
221
|
+
html = html.replace(" ", " ")
|
|
222
|
+
html = html.replace("&", "&")
|
|
223
|
+
html = html.replace("<", "<")
|
|
224
|
+
html = html.replace(">", ">")
|
|
225
|
+
html = html.replace(""", '"')
|
|
226
|
+
html = html.replace("'", "'")
|
|
227
|
+
# Normalize whitespace
|
|
228
|
+
html = re.sub(r"\s+", " ", html)
|
|
229
|
+
return html.strip()
|
|
230
|
+
|
|
231
|
+
def _truncate_content(self, content: str) -> str:
|
|
232
|
+
"""Truncate content if it exceeds max_content_length.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
content: The content to potentially truncate
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
Original or truncated content with notice
|
|
239
|
+
"""
|
|
240
|
+
if self.max_content_length is None or len(content) <= self.max_content_length:
|
|
241
|
+
return content
|
|
242
|
+
|
|
243
|
+
truncated = content[: self.max_content_length]
|
|
244
|
+
return f"{truncated}\n\n[Content truncated. Original length: {len(content)} characters. Showing first {self.max_content_length} characters.]"
|
|
245
|
+
|
|
171
246
|
def get_page_content(self, connect_url: Optional[str] = None) -> str:
|
|
172
|
-
"""Gets the
|
|
247
|
+
"""Gets the content of the current page.
|
|
173
248
|
|
|
174
249
|
Args:
|
|
175
250
|
connect_url (str, optional): The connection URL from an existing session
|
|
176
251
|
|
|
177
252
|
Returns:
|
|
178
|
-
The page HTML
|
|
253
|
+
The page content (text-only if parse_html=True, otherwise raw HTML)
|
|
179
254
|
"""
|
|
180
255
|
try:
|
|
181
256
|
self._initialize_browser(connect_url)
|
|
182
|
-
|
|
257
|
+
if not self._page:
|
|
258
|
+
return ""
|
|
259
|
+
|
|
260
|
+
raw_content = self._page.content()
|
|
261
|
+
|
|
262
|
+
if self.parse_html:
|
|
263
|
+
content = self._extract_text_content(raw_content)
|
|
264
|
+
else:
|
|
265
|
+
content = raw_content
|
|
266
|
+
|
|
267
|
+
return self._truncate_content(content)
|
|
183
268
|
except Exception as e:
|
|
184
269
|
self._cleanup()
|
|
185
270
|
raise e
|
|
186
271
|
|
|
187
272
|
def close_session(self) -> str:
|
|
188
273
|
"""Closes a browser session.
|
|
189
|
-
|
|
190
|
-
session_id (str, optional): The session ID to close. If not provided, will use the current session.
|
|
274
|
+
|
|
191
275
|
Returns:
|
|
192
276
|
JSON string with closure status
|
|
193
277
|
"""
|
|
@@ -207,3 +291,128 @@ class BrowserbaseTools(Toolkit):
|
|
|
207
291
|
)
|
|
208
292
|
except Exception as e:
|
|
209
293
|
return json.dumps({"status": "warning", "message": f"Cleanup completed with warning: {str(e)}"})
|
|
294
|
+
|
|
295
|
+
async def _ainitialize_browser(self, connect_url: Optional[str] = None):
|
|
296
|
+
"""
|
|
297
|
+
Initialize async browser connection if not already initialized.
|
|
298
|
+
Use provided connect_url or ensure we have a session with a connect_url
|
|
299
|
+
"""
|
|
300
|
+
try:
|
|
301
|
+
from playwright.async_api import async_playwright # type: ignore[import-not-found]
|
|
302
|
+
except ImportError:
|
|
303
|
+
raise ImportError(
|
|
304
|
+
"`playwright` not installed. Please install using `pip install playwright` and run `playwright install`"
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
if connect_url:
|
|
308
|
+
self._connect_url = connect_url if connect_url else "" # type: ignore
|
|
309
|
+
elif not self._connect_url:
|
|
310
|
+
self._ensure_session()
|
|
311
|
+
|
|
312
|
+
if not self._async_playwright:
|
|
313
|
+
self._async_playwright = await async_playwright().start() # type: ignore
|
|
314
|
+
if self._async_playwright:
|
|
315
|
+
self._async_browser = await self._async_playwright.chromium.connect_over_cdp(self._connect_url)
|
|
316
|
+
context = self._async_browser.contexts[0] if self._async_browser else None
|
|
317
|
+
if context:
|
|
318
|
+
self._async_page = context.pages[0] if context.pages else await context.new_page()
|
|
319
|
+
|
|
320
|
+
async def _acleanup(self):
|
|
321
|
+
"""Clean up async browser resources."""
|
|
322
|
+
if self._async_browser:
|
|
323
|
+
await self._async_browser.close()
|
|
324
|
+
self._async_browser = None
|
|
325
|
+
if self._async_playwright:
|
|
326
|
+
await self._async_playwright.stop()
|
|
327
|
+
self._async_playwright = None
|
|
328
|
+
self._async_page = None
|
|
329
|
+
|
|
330
|
+
async def anavigate_to(self, url: str, connect_url: Optional[str] = None) -> str:
|
|
331
|
+
"""Navigates to a URL asynchronously.
|
|
332
|
+
|
|
333
|
+
Args:
|
|
334
|
+
url (str): The URL to navigate to
|
|
335
|
+
connect_url (str, optional): The connection URL from an existing session
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
JSON string with navigation status
|
|
339
|
+
"""
|
|
340
|
+
try:
|
|
341
|
+
await self._ainitialize_browser(connect_url)
|
|
342
|
+
if self._async_page:
|
|
343
|
+
await self._async_page.goto(url, wait_until="networkidle")
|
|
344
|
+
title = await self._async_page.title() if self._async_page else ""
|
|
345
|
+
result = {"status": "complete", "title": title, "url": url}
|
|
346
|
+
return json.dumps(result)
|
|
347
|
+
except Exception as e:
|
|
348
|
+
await self._acleanup()
|
|
349
|
+
raise e
|
|
350
|
+
|
|
351
|
+
async def ascreenshot(self, path: str, full_page: bool = True, connect_url: Optional[str] = None) -> str:
|
|
352
|
+
"""Takes a screenshot of the current page asynchronously.
|
|
353
|
+
|
|
354
|
+
Args:
|
|
355
|
+
path (str): Where to save the screenshot
|
|
356
|
+
full_page (bool): Whether to capture the full page
|
|
357
|
+
connect_url (str, optional): The connection URL from an existing session
|
|
358
|
+
|
|
359
|
+
Returns:
|
|
360
|
+
JSON string confirming screenshot was saved
|
|
361
|
+
"""
|
|
362
|
+
try:
|
|
363
|
+
await self._ainitialize_browser(connect_url)
|
|
364
|
+
if self._async_page:
|
|
365
|
+
await self._async_page.screenshot(path=path, full_page=full_page)
|
|
366
|
+
return json.dumps({"status": "success", "path": path})
|
|
367
|
+
except Exception as e:
|
|
368
|
+
await self._acleanup()
|
|
369
|
+
raise e
|
|
370
|
+
|
|
371
|
+
async def aget_page_content(self, connect_url: Optional[str] = None) -> str:
|
|
372
|
+
"""Gets the content of the current page asynchronously.
|
|
373
|
+
|
|
374
|
+
Args:
|
|
375
|
+
connect_url (str, optional): The connection URL from an existing session
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
The page content (text-only if parse_html=True, otherwise raw HTML)
|
|
379
|
+
"""
|
|
380
|
+
try:
|
|
381
|
+
await self._ainitialize_browser(connect_url)
|
|
382
|
+
if not self._async_page:
|
|
383
|
+
return ""
|
|
384
|
+
|
|
385
|
+
raw_content = await self._async_page.content()
|
|
386
|
+
|
|
387
|
+
if self.parse_html:
|
|
388
|
+
content = self._extract_text_content(raw_content)
|
|
389
|
+
else:
|
|
390
|
+
content = raw_content
|
|
391
|
+
|
|
392
|
+
return self._truncate_content(content)
|
|
393
|
+
except Exception as e:
|
|
394
|
+
await self._acleanup()
|
|
395
|
+
raise e
|
|
396
|
+
|
|
397
|
+
async def aclose_session(self) -> str:
|
|
398
|
+
"""Closes a browser session asynchronously.
|
|
399
|
+
|
|
400
|
+
Returns:
|
|
401
|
+
JSON string with closure status
|
|
402
|
+
"""
|
|
403
|
+
try:
|
|
404
|
+
# First cleanup our local browser resources
|
|
405
|
+
await self._acleanup()
|
|
406
|
+
|
|
407
|
+
# Reset session state
|
|
408
|
+
self._session = None
|
|
409
|
+
self._connect_url = None
|
|
410
|
+
|
|
411
|
+
return json.dumps(
|
|
412
|
+
{
|
|
413
|
+
"status": "closed",
|
|
414
|
+
"message": "Browser resources cleaned up. Session will auto-close if not already closed.",
|
|
415
|
+
}
|
|
416
|
+
)
|
|
417
|
+
except Exception as e:
|
|
418
|
+
return json.dumps({"status": "warning", "message": f"Cleanup completed with warning: {str(e)}"})
|
agno/tools/crawl4ai.py
CHANGED
|
@@ -20,6 +20,7 @@ class Crawl4aiTools(Toolkit):
|
|
|
20
20
|
bm25_threshold: float = 1.0,
|
|
21
21
|
headless: bool = True,
|
|
22
22
|
wait_until: str = "domcontentloaded",
|
|
23
|
+
proxy_config: Optional[Dict[str, Any]] = None,
|
|
23
24
|
enable_crawl: bool = True,
|
|
24
25
|
all: bool = False,
|
|
25
26
|
**kwargs,
|
|
@@ -36,6 +37,7 @@ class Crawl4aiTools(Toolkit):
|
|
|
36
37
|
self.bm25_threshold = bm25_threshold
|
|
37
38
|
self.wait_until = wait_until
|
|
38
39
|
self.headless = headless
|
|
40
|
+
self.proxy_config = proxy_config or {}
|
|
39
41
|
|
|
40
42
|
def _build_config(self, search_query: Optional[str] = None) -> Dict[str, Any]:
|
|
41
43
|
"""Build CrawlerRunConfig parameters from toolkit settings."""
|
|
@@ -103,6 +105,7 @@ class Crawl4aiTools(Toolkit):
|
|
|
103
105
|
browser_config = BrowserConfig(
|
|
104
106
|
headless=self.headless,
|
|
105
107
|
verbose=False,
|
|
108
|
+
**self.proxy_config,
|
|
106
109
|
)
|
|
107
110
|
|
|
108
111
|
async with AsyncWebCrawler(config=browser_config) as crawler:
|
agno/tools/duckduckgo.py
CHANGED
|
@@ -1,36 +1,26 @@
|
|
|
1
|
-
import
|
|
2
|
-
from typing import Any, List, Optional
|
|
1
|
+
from typing import Optional
|
|
3
2
|
|
|
4
|
-
from agno.tools import
|
|
5
|
-
from agno.utils.log import log_debug
|
|
3
|
+
from agno.tools.websearch import WebSearchTools
|
|
6
4
|
|
|
7
|
-
try:
|
|
8
|
-
from ddgs import DDGS
|
|
9
|
-
except ImportError:
|
|
10
|
-
raise ImportError("`ddgs` not installed. Please install using `pip install ddgs`")
|
|
11
5
|
|
|
12
|
-
|
|
13
|
-
class DuckDuckGoTools(Toolkit):
|
|
6
|
+
class DuckDuckGoTools(WebSearchTools):
|
|
14
7
|
"""
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
DuckDuckGoTools is a convenience wrapper around WebSearchTools with the backend
|
|
9
|
+
defaulting to "duckduckgo".
|
|
17
10
|
Args:
|
|
18
|
-
enable_search (bool): Enable
|
|
19
|
-
enable_news (bool): Enable
|
|
20
|
-
modifier (Optional[str]): A modifier to be
|
|
11
|
+
enable_search (bool): Enable web search function.
|
|
12
|
+
enable_news (bool): Enable news search function.
|
|
13
|
+
modifier (Optional[str]): A modifier to be prepended to search queries.
|
|
21
14
|
fixed_max_results (Optional[int]): A fixed number of maximum results.
|
|
22
|
-
proxy (Optional[str]): Proxy to be used
|
|
15
|
+
proxy (Optional[str]): Proxy to be used for requests.
|
|
23
16
|
timeout (Optional[int]): The maximum number of seconds to wait for a response.
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
verify_ssl (bool): Whether to verify SSL certificates.
|
|
26
18
|
"""
|
|
27
19
|
|
|
28
20
|
def __init__(
|
|
29
21
|
self,
|
|
30
22
|
enable_search: bool = True,
|
|
31
23
|
enable_news: bool = True,
|
|
32
|
-
all: bool = False,
|
|
33
|
-
backend: str = "duckduckgo",
|
|
34
24
|
modifier: Optional[str] = None,
|
|
35
25
|
fixed_max_results: Optional[int] = None,
|
|
36
26
|
proxy: Optional[str] = None,
|
|
@@ -38,54 +28,18 @@ class DuckDuckGoTools(Toolkit):
|
|
|
38
28
|
verify_ssl: bool = True,
|
|
39
29
|
**kwargs,
|
|
40
30
|
):
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def duckduckgo_search(self, query: str, max_results: int = 5) -> str:
|
|
57
|
-
"""Use this function to search DDGS for a query.
|
|
58
|
-
|
|
59
|
-
Args:
|
|
60
|
-
query(str): The query to search for.
|
|
61
|
-
max_results (optional, default=5): The maximum number of results to return.
|
|
62
|
-
|
|
63
|
-
Returns:
|
|
64
|
-
The result from DDGS.
|
|
65
|
-
"""
|
|
66
|
-
actual_max_results = self.fixed_max_results or max_results
|
|
67
|
-
search_query = f"{self.modifier} {query}" if self.modifier else query
|
|
68
|
-
|
|
69
|
-
log_debug(f"Searching DDG for: {search_query} using backend: {self.backend}")
|
|
70
|
-
with DDGS(proxy=self.proxy, timeout=self.timeout, verify=self.verify_ssl) as ddgs:
|
|
71
|
-
results = ddgs.text(query=search_query, max_results=actual_max_results, backend=self.backend)
|
|
72
|
-
|
|
73
|
-
return json.dumps(results, indent=2)
|
|
74
|
-
|
|
75
|
-
def duckduckgo_news(self, query: str, max_results: int = 5) -> str:
|
|
76
|
-
"""Use this function to get the latest news from DDGS.
|
|
77
|
-
|
|
78
|
-
Args:
|
|
79
|
-
query(str): The query to search for.
|
|
80
|
-
max_results (optional, default=5): The maximum number of results to return.
|
|
81
|
-
|
|
82
|
-
Returns:
|
|
83
|
-
The latest news from DDGS.
|
|
84
|
-
"""
|
|
85
|
-
actual_max_results = self.fixed_max_results or max_results
|
|
86
|
-
|
|
87
|
-
log_debug(f"Searching DDG news for: {query} using backend: {self.backend}")
|
|
88
|
-
with DDGS(proxy=self.proxy, timeout=self.timeout, verify=self.verify_ssl) as ddgs:
|
|
89
|
-
results = ddgs.news(query=query, max_results=actual_max_results, backend=self.backend)
|
|
90
|
-
|
|
91
|
-
return json.dumps(results, indent=2)
|
|
31
|
+
super().__init__(
|
|
32
|
+
enable_search=enable_search,
|
|
33
|
+
enable_news=enable_news,
|
|
34
|
+
backend="duckduckgo",
|
|
35
|
+
modifier=modifier,
|
|
36
|
+
fixed_max_results=fixed_max_results,
|
|
37
|
+
proxy=proxy,
|
|
38
|
+
timeout=timeout,
|
|
39
|
+
verify_ssl=verify_ssl,
|
|
40
|
+
**kwargs,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Backward compatibility aliases for old method names
|
|
44
|
+
self.duckduckgo_search = self.web_search
|
|
45
|
+
self.duckduckgo_news = self.search_news
|
agno/tools/exa.py
CHANGED
|
@@ -27,14 +27,12 @@ class ExaTools(Toolkit):
|
|
|
27
27
|
all (bool): Enable all tools. Overrides individual flags when True. Default is False.
|
|
28
28
|
text (bool): Retrieve text content from results. Default is True.
|
|
29
29
|
text_length_limit (int): Max length of text content per result. Default is 1000.
|
|
30
|
-
highlights (bool): Include highlighted snippets. Deprecated since it was removed in the Exa API. It will be removed from Agno in a future release.
|
|
31
30
|
api_key (Optional[str]): Exa API key. Retrieved from `EXA_API_KEY` env variable if not provided.
|
|
32
31
|
num_results (Optional[int]): Default number of search results. Overrides individual searches if set.
|
|
33
32
|
start_crawl_date (Optional[str]): Include results crawled on/after this date (`YYYY-MM-DD`).
|
|
34
33
|
end_crawl_date (Optional[str]): Include results crawled on/before this date (`YYYY-MM-DD`).
|
|
35
34
|
start_published_date (Optional[str]): Include results published on/after this date (`YYYY-MM-DD`).
|
|
36
35
|
end_published_date (Optional[str]): Include results published on/before this date (`YYYY-MM-DD`).
|
|
37
|
-
use_autoprompt (Optional[bool]): Enable autoprompt features in queries. Deprecated since it was removed in the Exa API. It will be removed from Agno in a future release.
|
|
38
36
|
type (Optional[str]): Specify content type (e.g., article, blog, video).
|
|
39
37
|
category (Optional[str]): Filter results by category. Options are "company", "research paper", "news", "pdf", "github", "tweet", "personal site", "linkedin profile", "financial report".
|
|
40
38
|
include_domains (Optional[List[str]]): Restrict results to these domains.
|
|
@@ -54,7 +52,6 @@ class ExaTools(Toolkit):
|
|
|
54
52
|
all: bool = False,
|
|
55
53
|
text: bool = True,
|
|
56
54
|
text_length_limit: int = 1000,
|
|
57
|
-
highlights: Optional[bool] = None, # Deprecated
|
|
58
55
|
summary: bool = False,
|
|
59
56
|
api_key: Optional[str] = None,
|
|
60
57
|
num_results: Optional[int] = None,
|
|
@@ -63,7 +60,6 @@ class ExaTools(Toolkit):
|
|
|
63
60
|
end_crawl_date: Optional[str] = None,
|
|
64
61
|
start_published_date: Optional[str] = None,
|
|
65
62
|
end_published_date: Optional[str] = None,
|
|
66
|
-
use_autoprompt: Optional[bool] = None,
|
|
67
63
|
type: Optional[str] = None,
|
|
68
64
|
category: Optional[str] = None,
|
|
69
65
|
include_domains: Optional[List[str]] = None,
|
|
@@ -85,23 +81,6 @@ class ExaTools(Toolkit):
|
|
|
85
81
|
self.text: bool = text
|
|
86
82
|
self.text_length_limit: int = text_length_limit
|
|
87
83
|
|
|
88
|
-
if highlights:
|
|
89
|
-
import warnings
|
|
90
|
-
|
|
91
|
-
warnings.warn(
|
|
92
|
-
"The 'highlights' parameter is deprecated since it was removed in the Exa API. It will be removed from Agno in a future release.",
|
|
93
|
-
DeprecationWarning,
|
|
94
|
-
stacklevel=2,
|
|
95
|
-
)
|
|
96
|
-
if use_autoprompt:
|
|
97
|
-
import warnings
|
|
98
|
-
|
|
99
|
-
warnings.warn(
|
|
100
|
-
"The 'use_autoprompt' parameter is deprecated since it was removed in the Exa API. It will be removed from Agno in a future release.",
|
|
101
|
-
DeprecationWarning,
|
|
102
|
-
stacklevel=2,
|
|
103
|
-
)
|
|
104
|
-
|
|
105
84
|
self.summary: bool = summary
|
|
106
85
|
self.num_results: Optional[int] = num_results
|
|
107
86
|
self.livecrawl: str = livecrawl
|
agno/tools/file.py
CHANGED
|
@@ -24,8 +24,7 @@ class FileTools(Toolkit):
|
|
|
24
24
|
all: bool = False,
|
|
25
25
|
**kwargs,
|
|
26
26
|
):
|
|
27
|
-
self.base_dir: Path = base_dir or Path.cwd()
|
|
28
|
-
self.base_dir = self.base_dir.resolve()
|
|
27
|
+
self.base_dir: Path = (base_dir or Path.cwd()).resolve()
|
|
29
28
|
|
|
30
29
|
tools: List[Any] = []
|
|
31
30
|
self.max_file_length = max_file_length
|
|
@@ -49,6 +48,19 @@ class FileTools(Toolkit):
|
|
|
49
48
|
|
|
50
49
|
super().__init__(name="file_tools", tools=tools, **kwargs)
|
|
51
50
|
|
|
51
|
+
def check_escape(self, relative_path: str) -> Tuple[bool, Path]:
|
|
52
|
+
"""Check if the file path is within the base directory.
|
|
53
|
+
|
|
54
|
+
Alias for _check_path maintained for backward compatibility.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
relative_path: The file name or relative path to check.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Tuple of (is_safe, resolved_path). If not safe, returns base_dir as the path.
|
|
61
|
+
"""
|
|
62
|
+
return self._check_path(relative_path, self.base_dir)
|
|
63
|
+
|
|
52
64
|
def save_file(self, contents: str, file_name: str, overwrite: bool = True, encoding: str = "utf-8") -> str:
|
|
53
65
|
"""Saves the contents to a file called `file_name` and returns the file name if successful.
|
|
54
66
|
|
|
@@ -173,17 +185,6 @@ class FileTools(Toolkit):
|
|
|
173
185
|
log_error(f"Error removing {file_name}: {e}")
|
|
174
186
|
return f"Error removing file: {e}"
|
|
175
187
|
|
|
176
|
-
def check_escape(self, relative_path: str) -> Tuple[bool, Path]:
|
|
177
|
-
d = self.base_dir.joinpath(Path(relative_path)).resolve()
|
|
178
|
-
if self.base_dir == d:
|
|
179
|
-
return True, d
|
|
180
|
-
try:
|
|
181
|
-
d.relative_to(self.base_dir)
|
|
182
|
-
except ValueError:
|
|
183
|
-
log_error("Attempted to escape base_dir")
|
|
184
|
-
return False, self.base_dir
|
|
185
|
-
return True, d
|
|
186
|
-
|
|
187
188
|
def list_files(self, **kwargs) -> str:
|
|
188
189
|
"""Returns a list of files in directory
|
|
189
190
|
:param directory: (Optional) name of directory to list.
|