agno 2.2.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agno/__init__.py +8 -0
- agno/agent/__init__.py +51 -0
- agno/agent/agent.py +10405 -0
- agno/api/__init__.py +0 -0
- agno/api/agent.py +28 -0
- agno/api/api.py +40 -0
- agno/api/evals.py +22 -0
- agno/api/os.py +17 -0
- agno/api/routes.py +13 -0
- agno/api/schemas/__init__.py +9 -0
- agno/api/schemas/agent.py +16 -0
- agno/api/schemas/evals.py +16 -0
- agno/api/schemas/os.py +14 -0
- agno/api/schemas/response.py +6 -0
- agno/api/schemas/team.py +16 -0
- agno/api/schemas/utils.py +21 -0
- agno/api/schemas/workflows.py +16 -0
- agno/api/settings.py +53 -0
- agno/api/team.py +30 -0
- agno/api/workflow.py +28 -0
- agno/cloud/aws/base.py +214 -0
- agno/cloud/aws/s3/__init__.py +2 -0
- agno/cloud/aws/s3/api_client.py +43 -0
- agno/cloud/aws/s3/bucket.py +195 -0
- agno/cloud/aws/s3/object.py +57 -0
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/__init__.py +24 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +598 -0
- agno/db/dynamo/__init__.py +3 -0
- agno/db/dynamo/dynamo.py +2042 -0
- agno/db/dynamo/schemas.py +314 -0
- agno/db/dynamo/utils.py +743 -0
- agno/db/firestore/__init__.py +3 -0
- agno/db/firestore/firestore.py +1795 -0
- agno/db/firestore/schemas.py +140 -0
- agno/db/firestore/utils.py +376 -0
- agno/db/gcs_json/__init__.py +3 -0
- agno/db/gcs_json/gcs_json_db.py +1335 -0
- agno/db/gcs_json/utils.py +228 -0
- agno/db/in_memory/__init__.py +3 -0
- agno/db/in_memory/in_memory_db.py +1160 -0
- agno/db/in_memory/utils.py +230 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1328 -0
- agno/db/json/utils.py +230 -0
- agno/db/migrations/__init__.py +0 -0
- agno/db/migrations/v1_to_v2.py +635 -0
- agno/db/mongo/__init__.py +17 -0
- agno/db/mongo/async_mongo.py +2026 -0
- agno/db/mongo/mongo.py +1982 -0
- agno/db/mongo/schemas.py +87 -0
- agno/db/mongo/utils.py +259 -0
- agno/db/mysql/__init__.py +3 -0
- agno/db/mysql/mysql.py +2308 -0
- agno/db/mysql/schemas.py +138 -0
- agno/db/mysql/utils.py +355 -0
- agno/db/postgres/__init__.py +4 -0
- agno/db/postgres/async_postgres.py +1927 -0
- agno/db/postgres/postgres.py +2260 -0
- agno/db/postgres/schemas.py +139 -0
- agno/db/postgres/utils.py +442 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +1660 -0
- agno/db/redis/schemas.py +123 -0
- agno/db/redis/utils.py +346 -0
- agno/db/schemas/__init__.py +4 -0
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/evals.py +33 -0
- agno/db/schemas/knowledge.py +40 -0
- agno/db/schemas/memory.py +46 -0
- agno/db/schemas/metrics.py +0 -0
- agno/db/singlestore/__init__.py +3 -0
- agno/db/singlestore/schemas.py +130 -0
- agno/db/singlestore/singlestore.py +2272 -0
- agno/db/singlestore/utils.py +384 -0
- agno/db/sqlite/__init__.py +4 -0
- agno/db/sqlite/async_sqlite.py +2293 -0
- agno/db/sqlite/schemas.py +133 -0
- agno/db/sqlite/sqlite.py +2288 -0
- agno/db/sqlite/utils.py +431 -0
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +309 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1353 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +116 -0
- agno/debug.py +18 -0
- agno/eval/__init__.py +14 -0
- agno/eval/accuracy.py +834 -0
- agno/eval/performance.py +773 -0
- agno/eval/reliability.py +306 -0
- agno/eval/utils.py +119 -0
- agno/exceptions.py +161 -0
- agno/filters.py +354 -0
- agno/guardrails/__init__.py +6 -0
- agno/guardrails/base.py +19 -0
- agno/guardrails/openai.py +144 -0
- agno/guardrails/pii.py +94 -0
- agno/guardrails/prompt_injection.py +52 -0
- agno/integrations/__init__.py +0 -0
- agno/integrations/discord/__init__.py +3 -0
- agno/integrations/discord/client.py +203 -0
- agno/knowledge/__init__.py +5 -0
- agno/knowledge/chunking/__init__.py +0 -0
- agno/knowledge/chunking/agentic.py +79 -0
- agno/knowledge/chunking/document.py +91 -0
- agno/knowledge/chunking/fixed.py +57 -0
- agno/knowledge/chunking/markdown.py +151 -0
- agno/knowledge/chunking/recursive.py +63 -0
- agno/knowledge/chunking/row.py +39 -0
- agno/knowledge/chunking/semantic.py +86 -0
- agno/knowledge/chunking/strategy.py +165 -0
- agno/knowledge/content.py +74 -0
- agno/knowledge/document/__init__.py +5 -0
- agno/knowledge/document/base.py +58 -0
- agno/knowledge/embedder/__init__.py +5 -0
- agno/knowledge/embedder/aws_bedrock.py +343 -0
- agno/knowledge/embedder/azure_openai.py +210 -0
- agno/knowledge/embedder/base.py +23 -0
- agno/knowledge/embedder/cohere.py +323 -0
- agno/knowledge/embedder/fastembed.py +62 -0
- agno/knowledge/embedder/fireworks.py +13 -0
- agno/knowledge/embedder/google.py +258 -0
- agno/knowledge/embedder/huggingface.py +94 -0
- agno/knowledge/embedder/jina.py +182 -0
- agno/knowledge/embedder/langdb.py +22 -0
- agno/knowledge/embedder/mistral.py +206 -0
- agno/knowledge/embedder/nebius.py +13 -0
- agno/knowledge/embedder/ollama.py +154 -0
- agno/knowledge/embedder/openai.py +195 -0
- agno/knowledge/embedder/sentence_transformer.py +63 -0
- agno/knowledge/embedder/together.py +13 -0
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +165 -0
- agno/knowledge/knowledge.py +1988 -0
- agno/knowledge/reader/__init__.py +7 -0
- agno/knowledge/reader/arxiv_reader.py +81 -0
- agno/knowledge/reader/base.py +95 -0
- agno/knowledge/reader/csv_reader.py +166 -0
- agno/knowledge/reader/docx_reader.py +82 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +292 -0
- agno/knowledge/reader/firecrawl_reader.py +201 -0
- agno/knowledge/reader/json_reader.py +87 -0
- agno/knowledge/reader/markdown_reader.py +137 -0
- agno/knowledge/reader/pdf_reader.py +431 -0
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +313 -0
- agno/knowledge/reader/s3_reader.py +89 -0
- agno/knowledge/reader/tavily_reader.py +194 -0
- agno/knowledge/reader/text_reader.py +115 -0
- agno/knowledge/reader/web_search_reader.py +372 -0
- agno/knowledge/reader/website_reader.py +455 -0
- agno/knowledge/reader/wikipedia_reader.py +59 -0
- agno/knowledge/reader/youtube_reader.py +78 -0
- agno/knowledge/remote_content/__init__.py +0 -0
- agno/knowledge/remote_content/remote_content.py +88 -0
- agno/knowledge/reranker/__init__.py +3 -0
- agno/knowledge/reranker/base.py +14 -0
- agno/knowledge/reranker/cohere.py +64 -0
- agno/knowledge/reranker/infinity.py +195 -0
- agno/knowledge/reranker/sentence_transformer.py +54 -0
- agno/knowledge/types.py +39 -0
- agno/knowledge/utils.py +189 -0
- agno/media.py +462 -0
- agno/memory/__init__.py +3 -0
- agno/memory/manager.py +1327 -0
- agno/models/__init__.py +0 -0
- agno/models/aimlapi/__init__.py +5 -0
- agno/models/aimlapi/aimlapi.py +45 -0
- agno/models/anthropic/__init__.py +5 -0
- agno/models/anthropic/claude.py +757 -0
- agno/models/aws/__init__.py +15 -0
- agno/models/aws/bedrock.py +701 -0
- agno/models/aws/claude.py +378 -0
- agno/models/azure/__init__.py +18 -0
- agno/models/azure/ai_foundry.py +485 -0
- agno/models/azure/openai_chat.py +131 -0
- agno/models/base.py +2175 -0
- agno/models/cerebras/__init__.py +12 -0
- agno/models/cerebras/cerebras.py +501 -0
- agno/models/cerebras/cerebras_openai.py +112 -0
- agno/models/cohere/__init__.py +5 -0
- agno/models/cohere/chat.py +389 -0
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +57 -0
- agno/models/dashscope/__init__.py +5 -0
- agno/models/dashscope/dashscope.py +91 -0
- agno/models/deepinfra/__init__.py +5 -0
- agno/models/deepinfra/deepinfra.py +28 -0
- agno/models/deepseek/__init__.py +5 -0
- agno/models/deepseek/deepseek.py +61 -0
- agno/models/defaults.py +1 -0
- agno/models/fireworks/__init__.py +5 -0
- agno/models/fireworks/fireworks.py +26 -0
- agno/models/google/__init__.py +5 -0
- agno/models/google/gemini.py +1085 -0
- agno/models/groq/__init__.py +5 -0
- agno/models/groq/groq.py +556 -0
- agno/models/huggingface/__init__.py +5 -0
- agno/models/huggingface/huggingface.py +491 -0
- agno/models/ibm/__init__.py +5 -0
- agno/models/ibm/watsonx.py +422 -0
- agno/models/internlm/__init__.py +3 -0
- agno/models/internlm/internlm.py +26 -0
- agno/models/langdb/__init__.py +1 -0
- agno/models/langdb/langdb.py +48 -0
- agno/models/litellm/__init__.py +14 -0
- agno/models/litellm/chat.py +468 -0
- agno/models/litellm/litellm_openai.py +25 -0
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/lmstudio/__init__.py +5 -0
- agno/models/lmstudio/lmstudio.py +25 -0
- agno/models/message.py +434 -0
- agno/models/meta/__init__.py +12 -0
- agno/models/meta/llama.py +475 -0
- agno/models/meta/llama_openai.py +78 -0
- agno/models/metrics.py +120 -0
- agno/models/mistral/__init__.py +5 -0
- agno/models/mistral/mistral.py +432 -0
- agno/models/nebius/__init__.py +3 -0
- agno/models/nebius/nebius.py +54 -0
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/__init__.py +5 -0
- agno/models/nvidia/nvidia.py +28 -0
- agno/models/ollama/__init__.py +5 -0
- agno/models/ollama/chat.py +441 -0
- agno/models/openai/__init__.py +9 -0
- agno/models/openai/chat.py +883 -0
- agno/models/openai/like.py +27 -0
- agno/models/openai/responses.py +1050 -0
- agno/models/openrouter/__init__.py +5 -0
- agno/models/openrouter/openrouter.py +66 -0
- agno/models/perplexity/__init__.py +5 -0
- agno/models/perplexity/perplexity.py +187 -0
- agno/models/portkey/__init__.py +3 -0
- agno/models/portkey/portkey.py +81 -0
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +52 -0
- agno/models/response.py +199 -0
- agno/models/sambanova/__init__.py +5 -0
- agno/models/sambanova/sambanova.py +28 -0
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +25 -0
- agno/models/together/__init__.py +5 -0
- agno/models/together/together.py +25 -0
- agno/models/utils.py +266 -0
- agno/models/vercel/__init__.py +3 -0
- agno/models/vercel/v0.py +26 -0
- agno/models/vertexai/__init__.py +0 -0
- agno/models/vertexai/claude.py +70 -0
- agno/models/vllm/__init__.py +3 -0
- agno/models/vllm/vllm.py +78 -0
- agno/models/xai/__init__.py +3 -0
- agno/models/xai/xai.py +113 -0
- agno/os/__init__.py +3 -0
- agno/os/app.py +876 -0
- agno/os/auth.py +57 -0
- agno/os/config.py +104 -0
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/a2a/__init__.py +3 -0
- agno/os/interfaces/a2a/a2a.py +42 -0
- agno/os/interfaces/a2a/router.py +250 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/__init__.py +3 -0
- agno/os/interfaces/agui/agui.py +47 -0
- agno/os/interfaces/agui/router.py +144 -0
- agno/os/interfaces/agui/utils.py +534 -0
- agno/os/interfaces/base.py +25 -0
- agno/os/interfaces/slack/__init__.py +3 -0
- agno/os/interfaces/slack/router.py +148 -0
- agno/os/interfaces/slack/security.py +30 -0
- agno/os/interfaces/slack/slack.py +47 -0
- agno/os/interfaces/whatsapp/__init__.py +3 -0
- agno/os/interfaces/whatsapp/router.py +211 -0
- agno/os/interfaces/whatsapp/security.py +53 -0
- agno/os/interfaces/whatsapp/whatsapp.py +36 -0
- agno/os/mcp.py +292 -0
- agno/os/middleware/__init__.py +7 -0
- agno/os/middleware/jwt.py +233 -0
- agno/os/router.py +1763 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +430 -0
- agno/os/routers/evals/schemas.py +142 -0
- agno/os/routers/evals/utils.py +162 -0
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/__init__.py +3 -0
- agno/os/routers/knowledge/knowledge.py +997 -0
- agno/os/routers/knowledge/schemas.py +178 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +515 -0
- agno/os/routers/memory/schemas.py +62 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +190 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +997 -0
- agno/os/schema.py +1055 -0
- agno/os/settings.py +43 -0
- agno/os/utils.py +630 -0
- agno/py.typed +0 -0
- agno/reasoning/__init__.py +0 -0
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +67 -0
- agno/reasoning/deepseek.py +63 -0
- agno/reasoning/default.py +97 -0
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +71 -0
- agno/reasoning/helpers.py +63 -0
- agno/reasoning/ollama.py +67 -0
- agno/reasoning/openai.py +86 -0
- agno/reasoning/step.py +31 -0
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +787 -0
- agno/run/base.py +229 -0
- agno/run/cancel.py +81 -0
- agno/run/messages.py +32 -0
- agno/run/team.py +753 -0
- agno/run/workflow.py +708 -0
- agno/session/__init__.py +10 -0
- agno/session/agent.py +295 -0
- agno/session/summary.py +265 -0
- agno/session/team.py +392 -0
- agno/session/workflow.py +205 -0
- agno/team/__init__.py +37 -0
- agno/team/team.py +8793 -0
- agno/tools/__init__.py +10 -0
- agno/tools/agentql.py +120 -0
- agno/tools/airflow.py +69 -0
- agno/tools/api.py +122 -0
- agno/tools/apify.py +314 -0
- agno/tools/arxiv.py +127 -0
- agno/tools/aws_lambda.py +53 -0
- agno/tools/aws_ses.py +66 -0
- agno/tools/baidusearch.py +89 -0
- agno/tools/bitbucket.py +292 -0
- agno/tools/brandfetch.py +213 -0
- agno/tools/bravesearch.py +106 -0
- agno/tools/brightdata.py +367 -0
- agno/tools/browserbase.py +209 -0
- agno/tools/calcom.py +255 -0
- agno/tools/calculator.py +151 -0
- agno/tools/cartesia.py +187 -0
- agno/tools/clickup.py +244 -0
- agno/tools/confluence.py +240 -0
- agno/tools/crawl4ai.py +158 -0
- agno/tools/csv_toolkit.py +185 -0
- agno/tools/dalle.py +110 -0
- agno/tools/daytona.py +475 -0
- agno/tools/decorator.py +262 -0
- agno/tools/desi_vocal.py +108 -0
- agno/tools/discord.py +161 -0
- agno/tools/docker.py +716 -0
- agno/tools/duckdb.py +379 -0
- agno/tools/duckduckgo.py +91 -0
- agno/tools/e2b.py +703 -0
- agno/tools/eleven_labs.py +196 -0
- agno/tools/email.py +67 -0
- agno/tools/evm.py +129 -0
- agno/tools/exa.py +396 -0
- agno/tools/fal.py +127 -0
- agno/tools/file.py +240 -0
- agno/tools/file_generation.py +350 -0
- agno/tools/financial_datasets.py +288 -0
- agno/tools/firecrawl.py +143 -0
- agno/tools/function.py +1187 -0
- agno/tools/giphy.py +93 -0
- agno/tools/github.py +1760 -0
- agno/tools/gmail.py +922 -0
- agno/tools/google_bigquery.py +117 -0
- agno/tools/google_drive.py +270 -0
- agno/tools/google_maps.py +253 -0
- agno/tools/googlecalendar.py +674 -0
- agno/tools/googlesearch.py +98 -0
- agno/tools/googlesheets.py +377 -0
- agno/tools/hackernews.py +77 -0
- agno/tools/jina.py +101 -0
- agno/tools/jira.py +170 -0
- agno/tools/knowledge.py +218 -0
- agno/tools/linear.py +426 -0
- agno/tools/linkup.py +58 -0
- agno/tools/local_file_system.py +90 -0
- agno/tools/lumalab.py +183 -0
- agno/tools/mcp/__init__.py +10 -0
- agno/tools/mcp/mcp.py +331 -0
- agno/tools/mcp/multi_mcp.py +347 -0
- agno/tools/mcp/params.py +24 -0
- agno/tools/mcp_toolbox.py +284 -0
- agno/tools/mem0.py +193 -0
- agno/tools/memori.py +339 -0
- agno/tools/memory.py +419 -0
- agno/tools/mlx_transcribe.py +139 -0
- agno/tools/models/__init__.py +0 -0
- agno/tools/models/azure_openai.py +190 -0
- agno/tools/models/gemini.py +203 -0
- agno/tools/models/groq.py +158 -0
- agno/tools/models/morph.py +186 -0
- agno/tools/models/nebius.py +124 -0
- agno/tools/models_labs.py +195 -0
- agno/tools/moviepy_video.py +349 -0
- agno/tools/neo4j.py +134 -0
- agno/tools/newspaper.py +46 -0
- agno/tools/newspaper4k.py +93 -0
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +202 -0
- agno/tools/openbb.py +160 -0
- agno/tools/opencv.py +321 -0
- agno/tools/openweather.py +233 -0
- agno/tools/oxylabs.py +385 -0
- agno/tools/pandas.py +102 -0
- agno/tools/parallel.py +314 -0
- agno/tools/postgres.py +257 -0
- agno/tools/pubmed.py +188 -0
- agno/tools/python.py +205 -0
- agno/tools/reasoning.py +283 -0
- agno/tools/reddit.py +467 -0
- agno/tools/replicate.py +117 -0
- agno/tools/resend.py +62 -0
- agno/tools/scrapegraph.py +222 -0
- agno/tools/searxng.py +152 -0
- agno/tools/serpapi.py +116 -0
- agno/tools/serper.py +255 -0
- agno/tools/shell.py +53 -0
- agno/tools/slack.py +136 -0
- agno/tools/sleep.py +20 -0
- agno/tools/spider.py +116 -0
- agno/tools/sql.py +154 -0
- agno/tools/streamlit/__init__.py +0 -0
- agno/tools/streamlit/components.py +113 -0
- agno/tools/tavily.py +254 -0
- agno/tools/telegram.py +48 -0
- agno/tools/todoist.py +218 -0
- agno/tools/tool_registry.py +1 -0
- agno/tools/toolkit.py +146 -0
- agno/tools/trafilatura.py +388 -0
- agno/tools/trello.py +274 -0
- agno/tools/twilio.py +186 -0
- agno/tools/user_control_flow.py +78 -0
- agno/tools/valyu.py +228 -0
- agno/tools/visualization.py +467 -0
- agno/tools/webbrowser.py +28 -0
- agno/tools/webex.py +76 -0
- agno/tools/website.py +54 -0
- agno/tools/webtools.py +45 -0
- agno/tools/whatsapp.py +286 -0
- agno/tools/wikipedia.py +63 -0
- agno/tools/workflow.py +278 -0
- agno/tools/x.py +335 -0
- agno/tools/yfinance.py +257 -0
- agno/tools/youtube.py +184 -0
- agno/tools/zendesk.py +82 -0
- agno/tools/zep.py +454 -0
- agno/tools/zoom.py +382 -0
- agno/utils/__init__.py +0 -0
- agno/utils/agent.py +820 -0
- agno/utils/audio.py +49 -0
- agno/utils/certs.py +27 -0
- agno/utils/code_execution.py +11 -0
- agno/utils/common.py +132 -0
- agno/utils/dttm.py +13 -0
- agno/utils/enum.py +22 -0
- agno/utils/env.py +11 -0
- agno/utils/events.py +696 -0
- agno/utils/format_str.py +16 -0
- agno/utils/functions.py +166 -0
- agno/utils/gemini.py +426 -0
- agno/utils/hooks.py +57 -0
- agno/utils/http.py +74 -0
- agno/utils/json_schema.py +234 -0
- agno/utils/knowledge.py +36 -0
- agno/utils/location.py +19 -0
- agno/utils/log.py +255 -0
- agno/utils/mcp.py +214 -0
- agno/utils/media.py +352 -0
- agno/utils/merge_dict.py +41 -0
- agno/utils/message.py +118 -0
- agno/utils/models/__init__.py +0 -0
- agno/utils/models/ai_foundry.py +43 -0
- agno/utils/models/claude.py +358 -0
- agno/utils/models/cohere.py +87 -0
- agno/utils/models/llama.py +78 -0
- agno/utils/models/mistral.py +98 -0
- agno/utils/models/openai_responses.py +140 -0
- agno/utils/models/schema_utils.py +153 -0
- agno/utils/models/watsonx.py +41 -0
- agno/utils/openai.py +257 -0
- agno/utils/pickle.py +32 -0
- agno/utils/pprint.py +178 -0
- agno/utils/print_response/__init__.py +0 -0
- agno/utils/print_response/agent.py +842 -0
- agno/utils/print_response/team.py +1724 -0
- agno/utils/print_response/workflow.py +1668 -0
- agno/utils/prompts.py +111 -0
- agno/utils/reasoning.py +108 -0
- agno/utils/response.py +163 -0
- agno/utils/response_iterator.py +17 -0
- agno/utils/safe_formatter.py +24 -0
- agno/utils/serialize.py +32 -0
- agno/utils/shell.py +22 -0
- agno/utils/streamlit.py +487 -0
- agno/utils/string.py +231 -0
- agno/utils/team.py +139 -0
- agno/utils/timer.py +41 -0
- agno/utils/tools.py +102 -0
- agno/utils/web.py +23 -0
- agno/utils/whatsapp.py +305 -0
- agno/utils/yaml_io.py +25 -0
- agno/vectordb/__init__.py +3 -0
- agno/vectordb/base.py +127 -0
- agno/vectordb/cassandra/__init__.py +5 -0
- agno/vectordb/cassandra/cassandra.py +501 -0
- agno/vectordb/cassandra/extra_param_mixin.py +11 -0
- agno/vectordb/cassandra/index.py +13 -0
- agno/vectordb/chroma/__init__.py +5 -0
- agno/vectordb/chroma/chromadb.py +929 -0
- agno/vectordb/clickhouse/__init__.py +9 -0
- agno/vectordb/clickhouse/clickhousedb.py +835 -0
- agno/vectordb/clickhouse/index.py +9 -0
- agno/vectordb/couchbase/__init__.py +3 -0
- agno/vectordb/couchbase/couchbase.py +1442 -0
- agno/vectordb/distance.py +7 -0
- agno/vectordb/lancedb/__init__.py +6 -0
- agno/vectordb/lancedb/lance_db.py +995 -0
- agno/vectordb/langchaindb/__init__.py +5 -0
- agno/vectordb/langchaindb/langchaindb.py +163 -0
- agno/vectordb/lightrag/__init__.py +5 -0
- agno/vectordb/lightrag/lightrag.py +388 -0
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +166 -0
- agno/vectordb/milvus/__init__.py +4 -0
- agno/vectordb/milvus/milvus.py +1182 -0
- agno/vectordb/mongodb/__init__.py +9 -0
- agno/vectordb/mongodb/mongodb.py +1417 -0
- agno/vectordb/pgvector/__init__.py +12 -0
- agno/vectordb/pgvector/index.py +23 -0
- agno/vectordb/pgvector/pgvector.py +1462 -0
- agno/vectordb/pineconedb/__init__.py +5 -0
- agno/vectordb/pineconedb/pineconedb.py +747 -0
- agno/vectordb/qdrant/__init__.py +5 -0
- agno/vectordb/qdrant/qdrant.py +1134 -0
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +694 -0
- agno/vectordb/search.py +7 -0
- agno/vectordb/singlestore/__init__.py +10 -0
- agno/vectordb/singlestore/index.py +41 -0
- agno/vectordb/singlestore/singlestore.py +763 -0
- agno/vectordb/surrealdb/__init__.py +3 -0
- agno/vectordb/surrealdb/surrealdb.py +699 -0
- agno/vectordb/upstashdb/__init__.py +5 -0
- agno/vectordb/upstashdb/upstashdb.py +718 -0
- agno/vectordb/weaviate/__init__.py +8 -0
- agno/vectordb/weaviate/index.py +15 -0
- agno/vectordb/weaviate/weaviate.py +1005 -0
- agno/workflow/__init__.py +23 -0
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +738 -0
- agno/workflow/loop.py +735 -0
- agno/workflow/parallel.py +824 -0
- agno/workflow/router.py +702 -0
- agno/workflow/step.py +1432 -0
- agno/workflow/steps.py +592 -0
- agno/workflow/types.py +520 -0
- agno/workflow/workflow.py +4321 -0
- agno-2.2.13.dist-info/METADATA +614 -0
- agno-2.2.13.dist-info/RECORD +575 -0
- agno-2.2.13.dist-info/WHEEL +5 -0
- agno-2.2.13.dist-info/licenses/LICENSE +201 -0
- agno-2.2.13.dist-info/top_level.txt +1 -0
agno/tools/duckdb.py
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
3
|
+
|
|
4
|
+
from agno.tools import Toolkit
|
|
5
|
+
from agno.utils.log import log_debug, log_info, logger
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
import duckdb
|
|
9
|
+
except ImportError:
|
|
10
|
+
raise ImportError("`duckdb` not installed. Please install using `pip install duckdb`.")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DuckDbTools(Toolkit):
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
db_path: Optional[str] = None,
|
|
17
|
+
connection: Optional[duckdb.DuckDBPyConnection] = None,
|
|
18
|
+
init_commands: Optional[List] = None,
|
|
19
|
+
read_only: bool = False,
|
|
20
|
+
config: Optional[dict] = None,
|
|
21
|
+
**kwargs,
|
|
22
|
+
):
|
|
23
|
+
self.db_path: Optional[str] = db_path
|
|
24
|
+
self.read_only: bool = read_only
|
|
25
|
+
self.config: Optional[dict] = config
|
|
26
|
+
self._connection: Optional[duckdb.DuckDBPyConnection] = connection
|
|
27
|
+
self.init_commands: Optional[List] = init_commands
|
|
28
|
+
|
|
29
|
+
tools: List[Any] = [
|
|
30
|
+
self.show_tables,
|
|
31
|
+
self.describe_table,
|
|
32
|
+
self.inspect_query,
|
|
33
|
+
self.run_query,
|
|
34
|
+
self.create_table_from_path,
|
|
35
|
+
self.summarize_table,
|
|
36
|
+
self.export_table_to_path,
|
|
37
|
+
self.load_local_path_to_table,
|
|
38
|
+
self.load_local_csv_to_table,
|
|
39
|
+
self.load_s3_path_to_table,
|
|
40
|
+
self.load_s3_csv_to_table,
|
|
41
|
+
self.create_fts_index,
|
|
42
|
+
self.full_text_search,
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
super().__init__(name="duckdb_tools", tools=tools, **kwargs)
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def connection(self) -> duckdb.DuckDBPyConnection:
|
|
49
|
+
"""
|
|
50
|
+
Returns the duckdb connection
|
|
51
|
+
|
|
52
|
+
:return duckdb.DuckDBPyConnection: duckdb connection
|
|
53
|
+
"""
|
|
54
|
+
if self._connection is None:
|
|
55
|
+
connection_kwargs: Dict[str, Any] = {}
|
|
56
|
+
if self.db_path is not None:
|
|
57
|
+
connection_kwargs["database"] = self.db_path
|
|
58
|
+
if self.read_only:
|
|
59
|
+
connection_kwargs["read_only"] = self.read_only
|
|
60
|
+
if self.config is not None:
|
|
61
|
+
connection_kwargs["config"] = self.config
|
|
62
|
+
self._connection = duckdb.connect(**connection_kwargs)
|
|
63
|
+
try:
|
|
64
|
+
if self.init_commands is not None:
|
|
65
|
+
for command in self.init_commands:
|
|
66
|
+
self._connection.sql(command)
|
|
67
|
+
except Exception as e:
|
|
68
|
+
logger.exception(e)
|
|
69
|
+
logger.warning("Failed to run duckdb init commands")
|
|
70
|
+
|
|
71
|
+
return self._connection
|
|
72
|
+
|
|
73
|
+
def show_tables(self, show_tables: bool) -> str:
|
|
74
|
+
"""Function to show tables in the database
|
|
75
|
+
|
|
76
|
+
:param show_tables: Show tables in the database
|
|
77
|
+
:return: List of tables in the database
|
|
78
|
+
"""
|
|
79
|
+
if show_tables:
|
|
80
|
+
stmt = "SHOW TABLES;"
|
|
81
|
+
tables = self.run_query(stmt)
|
|
82
|
+
log_debug(f"Tables: {tables}")
|
|
83
|
+
return tables
|
|
84
|
+
return "No tables to show"
|
|
85
|
+
|
|
86
|
+
def describe_table(self, table: str) -> str:
|
|
87
|
+
"""Function to describe a table
|
|
88
|
+
|
|
89
|
+
:param table: Table to describe
|
|
90
|
+
:return: Description of the table
|
|
91
|
+
"""
|
|
92
|
+
stmt = f"DESCRIBE {table};"
|
|
93
|
+
table_description = self.run_query(stmt)
|
|
94
|
+
|
|
95
|
+
log_debug(f"Table description: {table_description}")
|
|
96
|
+
return f"{table}\n{table_description}"
|
|
97
|
+
|
|
98
|
+
def inspect_query(self, query: str) -> str:
|
|
99
|
+
"""Function to inspect a query and return the query plan. Always inspect your query before running them.
|
|
100
|
+
|
|
101
|
+
:param query: Query to inspect
|
|
102
|
+
:return: Query plan
|
|
103
|
+
"""
|
|
104
|
+
stmt = f"explain {query};"
|
|
105
|
+
explain_plan = self.run_query(stmt)
|
|
106
|
+
|
|
107
|
+
log_debug(f"Explain plan: {explain_plan}")
|
|
108
|
+
return explain_plan
|
|
109
|
+
|
|
110
|
+
def run_query(self, query: str) -> str:
|
|
111
|
+
"""Function that runs a query and returns the result.
|
|
112
|
+
|
|
113
|
+
:param query: SQL query to run
|
|
114
|
+
:return: Result of the query
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
# -*- Format the SQL Query
|
|
118
|
+
# Remove backticks
|
|
119
|
+
formatted_sql = query.replace("`", "")
|
|
120
|
+
# If there are multiple statements, only run the first one
|
|
121
|
+
formatted_sql = formatted_sql.split(";")[0]
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
log_info(f"Running: {formatted_sql}")
|
|
125
|
+
|
|
126
|
+
query_result = self.connection.sql(formatted_sql)
|
|
127
|
+
result_output = "No output"
|
|
128
|
+
if query_result is not None:
|
|
129
|
+
try:
|
|
130
|
+
results_as_python_objects = query_result.fetchall()
|
|
131
|
+
result_rows = []
|
|
132
|
+
for row in results_as_python_objects:
|
|
133
|
+
if len(row) == 1:
|
|
134
|
+
result_rows.append(str(row[0]))
|
|
135
|
+
else:
|
|
136
|
+
result_rows.append(",".join(str(x) for x in row))
|
|
137
|
+
|
|
138
|
+
result_data = "\n".join(result_rows)
|
|
139
|
+
result_output = ",".join(query_result.columns) + "\n" + result_data
|
|
140
|
+
except AttributeError:
|
|
141
|
+
result_output = str(query_result)
|
|
142
|
+
|
|
143
|
+
log_debug(f"Query result: {result_output}")
|
|
144
|
+
return result_output
|
|
145
|
+
except duckdb.ProgrammingError as e:
|
|
146
|
+
return str(e)
|
|
147
|
+
except duckdb.Error as e:
|
|
148
|
+
return str(e)
|
|
149
|
+
except Exception as e:
|
|
150
|
+
return str(e)
|
|
151
|
+
|
|
152
|
+
def summarize_table(self, table: str) -> str:
|
|
153
|
+
"""Function to compute a number of aggregates over a table.
|
|
154
|
+
The function launches a query that computes a number of aggregates over all columns,
|
|
155
|
+
including min, max, avg, std and approx_unique.
|
|
156
|
+
|
|
157
|
+
:param table: Table to summarize
|
|
158
|
+
:return: Summary of the table
|
|
159
|
+
"""
|
|
160
|
+
table_summary = self.run_query(f"SUMMARIZE {table};")
|
|
161
|
+
|
|
162
|
+
log_debug(f"Table description: {table_summary}")
|
|
163
|
+
return table_summary
|
|
164
|
+
|
|
165
|
+
def get_table_name_from_path(self, path: str) -> str:
|
|
166
|
+
"""Get the table name from a path
|
|
167
|
+
|
|
168
|
+
:param path: Path to get the table name from
|
|
169
|
+
:return: Table name
|
|
170
|
+
"""
|
|
171
|
+
# Get the file name from the path
|
|
172
|
+
path_obj = Path(path)
|
|
173
|
+
# Get the file name without extension from the path
|
|
174
|
+
table = path_obj.stem
|
|
175
|
+
# If the table isn't a valid SQL identifier, we'll need to use something else
|
|
176
|
+
table = table.replace("-", "_").replace(".", "_").replace(" ", "_").replace("/", "_")
|
|
177
|
+
|
|
178
|
+
return table
|
|
179
|
+
|
|
180
|
+
def create_table_from_path(self, path: str, table: Optional[str] = None, replace: bool = False) -> str:
|
|
181
|
+
"""Creates a table from a path
|
|
182
|
+
|
|
183
|
+
:param path: Path to load
|
|
184
|
+
:param table: Optional table name to use
|
|
185
|
+
:param replace: Whether to replace the table if it already exists
|
|
186
|
+
:return: Table name created
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
if table is None:
|
|
190
|
+
table = self.get_table_name_from_path(path)
|
|
191
|
+
|
|
192
|
+
log_debug(f"Creating table {table} from {path}")
|
|
193
|
+
create_statement = "CREATE TABLE IF NOT EXISTS"
|
|
194
|
+
if replace:
|
|
195
|
+
create_statement = "CREATE OR REPLACE TABLE"
|
|
196
|
+
|
|
197
|
+
# Check if the file is a CSV
|
|
198
|
+
if path.lower().endswith(".csv"):
|
|
199
|
+
create_statement += f" {table} AS SELECT * FROM read_csv('{path}', ignore_errors=false, auto_detect=true);"
|
|
200
|
+
else:
|
|
201
|
+
create_statement += f" {table} AS SELECT * FROM '{path}';"
|
|
202
|
+
|
|
203
|
+
self.run_query(create_statement)
|
|
204
|
+
log_debug(f"Created table {table} from {path}")
|
|
205
|
+
return table
|
|
206
|
+
|
|
207
|
+
def export_table_to_path(self, table: str, format: Optional[str] = "PARQUET", path: Optional[str] = None) -> str:
|
|
208
|
+
"""Save a table in a desired format (default: parquet)
|
|
209
|
+
If the path is provided, the table will be saved under that path.
|
|
210
|
+
Eg: If path is /tmp, the table will be saved as /tmp/table.parquet
|
|
211
|
+
Otherwise it will be saved in the current directory
|
|
212
|
+
|
|
213
|
+
:param table: Table to export
|
|
214
|
+
:param format: Format to export in (default: parquet)
|
|
215
|
+
:param path: Path to export to
|
|
216
|
+
:return: None
|
|
217
|
+
"""
|
|
218
|
+
if format is None:
|
|
219
|
+
format = "PARQUET"
|
|
220
|
+
|
|
221
|
+
log_debug(f"Exporting Table {table} as {format.upper()} to path {path}")
|
|
222
|
+
if path is None:
|
|
223
|
+
path = f"{table}.{format}"
|
|
224
|
+
else:
|
|
225
|
+
path = f"{path}/{table}.{format}"
|
|
226
|
+
export_statement = f"COPY (SELECT * FROM {table}) TO '{path}' (FORMAT {format.upper()});"
|
|
227
|
+
result = self.run_query(export_statement)
|
|
228
|
+
log_debug(f"Exported {table} to {path}/{table}")
|
|
229
|
+
return result
|
|
230
|
+
|
|
231
|
+
def load_local_path_to_table(self, path: str, table: Optional[str] = None) -> Tuple[str, str]:
|
|
232
|
+
"""Load a local file into duckdb
|
|
233
|
+
|
|
234
|
+
:param path: Path to load
|
|
235
|
+
:param table: Optional table name to use
|
|
236
|
+
:return: Table name, SQL statement used to load the file
|
|
237
|
+
"""
|
|
238
|
+
log_debug(f"Loading {path} into duckdb")
|
|
239
|
+
|
|
240
|
+
if table is None:
|
|
241
|
+
# Get the file name from the path
|
|
242
|
+
path_obj = Path(path)
|
|
243
|
+
# Get the file name without extension from the path
|
|
244
|
+
table = path_obj.stem
|
|
245
|
+
# If the table isn't a valid SQL identifier, we'll need to use something else
|
|
246
|
+
table = table.replace("-", "_").replace(".", "_").replace(" ", "_").replace("/", "_")
|
|
247
|
+
|
|
248
|
+
create_statement = f"CREATE OR REPLACE TABLE {table} AS SELECT * FROM '{path}';"
|
|
249
|
+
self.run_query(create_statement)
|
|
250
|
+
|
|
251
|
+
log_debug(f"Loaded {path} into duckdb as {table}")
|
|
252
|
+
return table, create_statement
|
|
253
|
+
|
|
254
|
+
def load_local_csv_to_table(
|
|
255
|
+
self, path: str, table: Optional[str] = None, delimiter: Optional[str] = None
|
|
256
|
+
) -> Tuple[str, str]:
|
|
257
|
+
"""Load a local CSV file into duckdb
|
|
258
|
+
|
|
259
|
+
:param path: Path to load
|
|
260
|
+
:param table: Optional table name to use
|
|
261
|
+
:param delimiter: Optional delimiter to use
|
|
262
|
+
:return: Table name, SQL statement used to load the file
|
|
263
|
+
"""
|
|
264
|
+
log_debug(f"Loading {path} into duckdb")
|
|
265
|
+
|
|
266
|
+
if table is None:
|
|
267
|
+
# Get the file name from the path
|
|
268
|
+
path_obj = Path(path)
|
|
269
|
+
# Get the file name without extension from the path
|
|
270
|
+
table = path_obj.stem
|
|
271
|
+
# If the table isn't a valid SQL identifier, we'll need to use something else
|
|
272
|
+
table = table.replace("-", "_").replace(".", "_").replace(" ", "_").replace("/", "_")
|
|
273
|
+
|
|
274
|
+
select_statement = f"SELECT * FROM read_csv('{path}', ignore_errors=false, auto_detect=true"
|
|
275
|
+
if delimiter is not None:
|
|
276
|
+
select_statement += f", delim='{delimiter}')"
|
|
277
|
+
else:
|
|
278
|
+
select_statement += ")"
|
|
279
|
+
|
|
280
|
+
create_statement = f"CREATE OR REPLACE TABLE {table} AS {select_statement};"
|
|
281
|
+
self.run_query(create_statement)
|
|
282
|
+
|
|
283
|
+
log_debug(f"Loaded CSV {path} into duckdb as {table}")
|
|
284
|
+
return table, create_statement
|
|
285
|
+
|
|
286
|
+
def load_s3_path_to_table(self, path: str, table: Optional[str] = None) -> Tuple[str, str]:
|
|
287
|
+
"""Load a file from S3 into duckdb
|
|
288
|
+
|
|
289
|
+
:param path: S3 path to load
|
|
290
|
+
:param table: Optional table name to use
|
|
291
|
+
:return: Table name, SQL statement used to load the file
|
|
292
|
+
"""
|
|
293
|
+
log_debug(f"Loading {path} into duckdb")
|
|
294
|
+
|
|
295
|
+
if table is None:
|
|
296
|
+
# Get the file name from the path
|
|
297
|
+
path_obj = Path(path)
|
|
298
|
+
# Get the file name without extension from the path
|
|
299
|
+
table = path_obj.stem
|
|
300
|
+
# If the table isn't a valid SQL identifier, we'll need to use something else
|
|
301
|
+
table = table.replace("-", "_").replace(".", "_").replace(" ", "_").replace("/", "_")
|
|
302
|
+
|
|
303
|
+
create_statement = f"CREATE OR REPLACE TABLE {table} AS SELECT * FROM '{path}';"
|
|
304
|
+
self.run_query(create_statement)
|
|
305
|
+
|
|
306
|
+
log_debug(f"Loaded {path} into duckdb as {table}")
|
|
307
|
+
return table, create_statement
|
|
308
|
+
|
|
309
|
+
def load_s3_csv_to_table(
|
|
310
|
+
self, path: str, table: Optional[str] = None, delimiter: Optional[str] = None
|
|
311
|
+
) -> Tuple[str, str]:
|
|
312
|
+
"""Load a CSV file from S3 into duckdb
|
|
313
|
+
|
|
314
|
+
:param path: S3 path to load
|
|
315
|
+
:param table: Optional table name to use
|
|
316
|
+
:return: Table name, SQL statement used to load the file
|
|
317
|
+
"""
|
|
318
|
+
log_debug(f"Loading {path} into duckdb")
|
|
319
|
+
|
|
320
|
+
if table is None:
|
|
321
|
+
# Get the file name from the path
|
|
322
|
+
path_obj = Path(path)
|
|
323
|
+
# Get the file name without extension from the path
|
|
324
|
+
table = path_obj.stem
|
|
325
|
+
# If the table isn't a valid SQL identifier, we'll need to use something else
|
|
326
|
+
table = table.replace("-", "_").replace(".", "_").replace(" ", "_").replace("/", "_")
|
|
327
|
+
|
|
328
|
+
select_statement = f"SELECT * FROM read_csv('{path}', ignore_errors=false, auto_detect=true"
|
|
329
|
+
if delimiter is not None:
|
|
330
|
+
select_statement += f", delim='{delimiter}')"
|
|
331
|
+
else:
|
|
332
|
+
select_statement += ")"
|
|
333
|
+
|
|
334
|
+
create_statement = f"CREATE OR REPLACE TABLE {table} AS {select_statement};"
|
|
335
|
+
self.run_query(create_statement)
|
|
336
|
+
|
|
337
|
+
log_debug(f"Loaded CSV {path} into duckdb as {table}")
|
|
338
|
+
return table, create_statement
|
|
339
|
+
|
|
340
|
+
def create_fts_index(self, table: str, unique_key: str, input_values: list[str]) -> str:
|
|
341
|
+
"""Create a full text search index on a table
|
|
342
|
+
|
|
343
|
+
:param table: Table to create the index on
|
|
344
|
+
:param unique_key: Unique key to use
|
|
345
|
+
:param input_values: Values to index
|
|
346
|
+
:return: None
|
|
347
|
+
"""
|
|
348
|
+
log_debug(f"Creating FTS index on {table} for {input_values}")
|
|
349
|
+
self.run_query("INSTALL fts;")
|
|
350
|
+
log_debug("Installed FTS extension")
|
|
351
|
+
self.run_query("LOAD fts;")
|
|
352
|
+
log_debug("Loaded FTS extension")
|
|
353
|
+
|
|
354
|
+
create_fts_index_statement = f"PRAGMA create_fts_index('{table}', '{unique_key}', '{input_values}');"
|
|
355
|
+
log_debug(f"Running {create_fts_index_statement}")
|
|
356
|
+
result = self.run_query(create_fts_index_statement)
|
|
357
|
+
log_debug(f"Created FTS index on {table} for {input_values}")
|
|
358
|
+
|
|
359
|
+
return result
|
|
360
|
+
|
|
361
|
+
def full_text_search(self, table: str, unique_key: str, search_text: str) -> str:
|
|
362
|
+
"""Full text Search in a table column for a specific text/keyword
|
|
363
|
+
|
|
364
|
+
:param table: Table to search
|
|
365
|
+
:param unique_key: Unique key to use
|
|
366
|
+
:param search_text: Text to search
|
|
367
|
+
:return: None
|
|
368
|
+
"""
|
|
369
|
+
log_debug(f"Running full_text_search for {search_text} in {table}")
|
|
370
|
+
search_text_statement = f"""SELECT fts_main_corpus.match_bm25({unique_key}, '{search_text}') AS score,*
|
|
371
|
+
FROM {table}
|
|
372
|
+
WHERE score IS NOT NULL
|
|
373
|
+
ORDER BY score;"""
|
|
374
|
+
|
|
375
|
+
log_debug(f"Running {search_text_statement}")
|
|
376
|
+
result = self.run_query(search_text_statement)
|
|
377
|
+
log_debug(f"Search results for {search_text} in {table}")
|
|
378
|
+
|
|
379
|
+
return result
|
agno/tools/duckduckgo.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Any, List, Optional
|
|
3
|
+
|
|
4
|
+
from agno.tools import Toolkit
|
|
5
|
+
from agno.utils.log import log_debug
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
from ddgs import DDGS
|
|
9
|
+
except ImportError:
|
|
10
|
+
raise ImportError("`ddgs` not installed. Please install using `pip install ddgs`")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DuckDuckGoTools(Toolkit):
|
|
14
|
+
"""
|
|
15
|
+
DuckDuckGo is a toolkit for searching using DuckDuckGo easily.
|
|
16
|
+
It uses the meta-search library DDGS, so it also has access to other backends.
|
|
17
|
+
Args:
|
|
18
|
+
enable_search (bool): Enable DDGS search function.
|
|
19
|
+
enable_news (bool): Enable DDGS news function.
|
|
20
|
+
modifier (Optional[str]): A modifier to be used in the search request.
|
|
21
|
+
fixed_max_results (Optional[int]): A fixed number of maximum results.
|
|
22
|
+
proxy (Optional[str]): Proxy to be used in the search request.
|
|
23
|
+
timeout (Optional[int]): The maximum number of seconds to wait for a response.
|
|
24
|
+
backend (Optional[str]): The backend to be used in the search request.
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
enable_search: bool = True,
|
|
31
|
+
enable_news: bool = True,
|
|
32
|
+
all: bool = False,
|
|
33
|
+
backend: str = "duckduckgo",
|
|
34
|
+
modifier: Optional[str] = None,
|
|
35
|
+
fixed_max_results: Optional[int] = None,
|
|
36
|
+
proxy: Optional[str] = None,
|
|
37
|
+
timeout: Optional[int] = 10,
|
|
38
|
+
verify_ssl: bool = True,
|
|
39
|
+
**kwargs,
|
|
40
|
+
):
|
|
41
|
+
self.proxy: Optional[str] = proxy
|
|
42
|
+
self.timeout: Optional[int] = timeout
|
|
43
|
+
self.fixed_max_results: Optional[int] = fixed_max_results
|
|
44
|
+
self.modifier: Optional[str] = modifier
|
|
45
|
+
self.verify_ssl: bool = verify_ssl
|
|
46
|
+
self.backend: str = backend
|
|
47
|
+
|
|
48
|
+
tools: List[Any] = []
|
|
49
|
+
if all or enable_search:
|
|
50
|
+
tools.append(self.duckduckgo_search)
|
|
51
|
+
if all or enable_news:
|
|
52
|
+
tools.append(self.duckduckgo_news)
|
|
53
|
+
|
|
54
|
+
super().__init__(name="duckduckgo", tools=tools, **kwargs)
|
|
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)
|