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/linear.py
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
from os import getenv
|
|
2
|
+
from typing import Any, List, Optional
|
|
3
|
+
|
|
4
|
+
import requests
|
|
5
|
+
|
|
6
|
+
from agno.tools import Toolkit
|
|
7
|
+
from agno.utils.log import log_info, logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LinearTools(Toolkit):
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
api_key: Optional[str] = None,
|
|
14
|
+
**kwargs,
|
|
15
|
+
):
|
|
16
|
+
self.api_key = api_key or getenv("LINEAR_API_KEY")
|
|
17
|
+
|
|
18
|
+
if not self.api_key:
|
|
19
|
+
raise ValueError("Linear API key is required")
|
|
20
|
+
|
|
21
|
+
self.endpoint = "https://api.linear.app/graphql"
|
|
22
|
+
self.headers = {"Authorization": f"{self.api_key}"}
|
|
23
|
+
|
|
24
|
+
tools: List[Any] = [
|
|
25
|
+
self.get_user_details,
|
|
26
|
+
self.get_teams_details,
|
|
27
|
+
self.get_issue_details,
|
|
28
|
+
self.create_issue,
|
|
29
|
+
self.update_issue,
|
|
30
|
+
self.get_user_assigned_issues,
|
|
31
|
+
self.get_workflow_issues,
|
|
32
|
+
self.get_high_priority_issues,
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
super().__init__(name="linear_tools", tools=tools, **kwargs)
|
|
36
|
+
|
|
37
|
+
def _execute_query(self, query, variables=None):
|
|
38
|
+
"""Helper method to execute GraphQL queries with optional variables."""
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
response = requests.post(self.endpoint, json={"query": query, "variables": variables}, headers=self.headers)
|
|
42
|
+
response.raise_for_status()
|
|
43
|
+
|
|
44
|
+
data = response.json()
|
|
45
|
+
|
|
46
|
+
if "errors" in data:
|
|
47
|
+
logger.error(f"GraphQL Error: {data['errors']}")
|
|
48
|
+
raise Exception(f"GraphQL Error: {data['errors']}")
|
|
49
|
+
|
|
50
|
+
log_info("GraphQL query executed successfully.")
|
|
51
|
+
return data.get("data")
|
|
52
|
+
|
|
53
|
+
except requests.exceptions.RequestException as e:
|
|
54
|
+
logger.error(f"Request error: {e}")
|
|
55
|
+
raise
|
|
56
|
+
|
|
57
|
+
except Exception as e:
|
|
58
|
+
logger.error(f"Unexpected error: {e}")
|
|
59
|
+
raise
|
|
60
|
+
|
|
61
|
+
def get_user_details(self) -> Optional[str]:
|
|
62
|
+
"""
|
|
63
|
+
Fetch authenticated user details.
|
|
64
|
+
It will return the user's unique ID, name, and email address from the viewer object in the GraphQL response.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
str or None: A string containing user details like user id, name, and email.
|
|
68
|
+
|
|
69
|
+
Raises:
|
|
70
|
+
Exception: If an error occurs during the query execution or data retrieval.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
query = """
|
|
74
|
+
query Me {
|
|
75
|
+
viewer {
|
|
76
|
+
id
|
|
77
|
+
name
|
|
78
|
+
email
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
response = self._execute_query(query)
|
|
85
|
+
|
|
86
|
+
if response.get("viewer"):
|
|
87
|
+
user = response["viewer"]
|
|
88
|
+
log_info(
|
|
89
|
+
f"Retrieved authenticated user details with name: {user['name']}, ID: {user['id']}, Email: {user['email']}"
|
|
90
|
+
)
|
|
91
|
+
return str(user)
|
|
92
|
+
else:
|
|
93
|
+
logger.error("Failed to retrieve the current user details")
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
except Exception as e:
|
|
97
|
+
logger.error(f"Error fetching authenticated user details: {e}")
|
|
98
|
+
raise
|
|
99
|
+
|
|
100
|
+
def get_teams_details(self) -> Optional[str]:
|
|
101
|
+
"""
|
|
102
|
+
Fetch the list of authenticated teams.
|
|
103
|
+
It will return the unique ID and team name for each team, from the viewer object in the GraphQL response.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
str or None: A dictionary containing team details like team name, id.
|
|
107
|
+
|
|
108
|
+
Raises:
|
|
109
|
+
Exception: If an error occurs during the query execution or data retrieval.
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
query = """
|
|
113
|
+
query Teams {
|
|
114
|
+
teams {
|
|
115
|
+
nodes {
|
|
116
|
+
id
|
|
117
|
+
name
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
response = self._execute_query(query)
|
|
125
|
+
|
|
126
|
+
if response.get("teams"):
|
|
127
|
+
teams = response["teams"]["nodes"]
|
|
128
|
+
log_info(f"Retrieved authenticated team details: {teams}")
|
|
129
|
+
return str(teams)
|
|
130
|
+
else:
|
|
131
|
+
logger.error("Failed to retrieve the current user details")
|
|
132
|
+
return None
|
|
133
|
+
|
|
134
|
+
except Exception as e:
|
|
135
|
+
logger.error(f"Error fetching authenticated user details: {e}")
|
|
136
|
+
raise
|
|
137
|
+
|
|
138
|
+
def get_issue_details(self, issue_id: str) -> Optional[str]:
|
|
139
|
+
"""
|
|
140
|
+
Retrieve details of a specific issue by issue ID.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
issue_id (str): The unique identifier of the issue to retrieve.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
str or None: A string containing issue details like issue id, issue title, and issue description.
|
|
147
|
+
Returns `None` if the issue is not found.
|
|
148
|
+
|
|
149
|
+
Raises:
|
|
150
|
+
Exception: If an error occurs during the query execution or data retrieval.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
query = """
|
|
154
|
+
query IssueDetails ($issueId: String!){
|
|
155
|
+
issue(id: $issueId) {
|
|
156
|
+
id
|
|
157
|
+
title
|
|
158
|
+
description
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
"""
|
|
162
|
+
variables = {"issueId": issue_id}
|
|
163
|
+
try:
|
|
164
|
+
response = self._execute_query(query, variables)
|
|
165
|
+
|
|
166
|
+
if response.get("issue"):
|
|
167
|
+
issue = response["issue"]
|
|
168
|
+
log_info(f"Issue '{issue['title']}' retrieved successfully with ID {issue['id']}.")
|
|
169
|
+
return str(issue)
|
|
170
|
+
else:
|
|
171
|
+
logger.error(f"Failed to retrieve issue with ID {issue_id}.")
|
|
172
|
+
return None
|
|
173
|
+
|
|
174
|
+
except Exception as e:
|
|
175
|
+
logger.error(f"Error retrieving issue with ID {issue_id}: {e}")
|
|
176
|
+
raise
|
|
177
|
+
|
|
178
|
+
def create_issue(
|
|
179
|
+
self,
|
|
180
|
+
title: str,
|
|
181
|
+
description: str,
|
|
182
|
+
team_id: str,
|
|
183
|
+
project_id: Optional[str] = None,
|
|
184
|
+
assignee_id: Optional[str] = None,
|
|
185
|
+
) -> Optional[str]:
|
|
186
|
+
"""
|
|
187
|
+
Create a new issue within a specific project and team.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
title (str): The title of the new issue.
|
|
191
|
+
description (str): The description of the new issue.
|
|
192
|
+
team_id (str): The unique identifier of the team in which to create the issue.
|
|
193
|
+
project_id (Optional[str]): The ID of the project (optional).
|
|
194
|
+
assignee_id (Optional[str]): The ID of the assignee (optional).
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
str or None: A string containing the created issue's details like issue id and issue title.
|
|
198
|
+
Returns `None` if the issue creation fails.
|
|
199
|
+
|
|
200
|
+
Raises:
|
|
201
|
+
Exception: If an error occurs during the mutation execution or data retrieval.
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
query = """
|
|
205
|
+
mutation IssueCreate ($title: String!, $description: String!, $teamId: String!, $projectId: String, $assigneeId: String){
|
|
206
|
+
issueCreate(
|
|
207
|
+
input: { title: $title, description: $description, teamId: $teamId, projectId: $projectId, assigneeId: $assigneeId}
|
|
208
|
+
) {
|
|
209
|
+
success
|
|
210
|
+
issue {
|
|
211
|
+
id
|
|
212
|
+
title
|
|
213
|
+
url
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
"""
|
|
218
|
+
|
|
219
|
+
variables = {
|
|
220
|
+
"title": title,
|
|
221
|
+
"description": description,
|
|
222
|
+
"teamId": team_id,
|
|
223
|
+
}
|
|
224
|
+
if project_id is not None:
|
|
225
|
+
variables["projectId"] = project_id
|
|
226
|
+
if assignee_id is not None:
|
|
227
|
+
variables["assigneeId"] = assignee_id
|
|
228
|
+
|
|
229
|
+
try:
|
|
230
|
+
response = self._execute_query(query, variables)
|
|
231
|
+
log_info(f"Response: {response}")
|
|
232
|
+
|
|
233
|
+
if response["issueCreate"]["success"]:
|
|
234
|
+
issue = response["issueCreate"]["issue"]
|
|
235
|
+
log_info(f"Issue '{issue['title']}' created successfully with ID {issue['id']}")
|
|
236
|
+
return str(issue)
|
|
237
|
+
else:
|
|
238
|
+
logger.error("Issue creation failed.")
|
|
239
|
+
return None
|
|
240
|
+
|
|
241
|
+
except Exception as e:
|
|
242
|
+
logger.error(f"Error creating issue '{title}' for team ID {team_id}: {e}")
|
|
243
|
+
raise
|
|
244
|
+
|
|
245
|
+
def update_issue(self, issue_id: str, title: Optional[str]) -> Optional[str]:
|
|
246
|
+
"""
|
|
247
|
+
Update the title or state of a specific issue by issue ID.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
issue_id (str): The unique identifier of the issue to update.
|
|
251
|
+
title (str, optional): The new title for the issue. If None, the title remains unchanged.
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
str or None: A string containing the updated issue's details with issue id, issue title, and issue state (which includes `id` and `name`).
|
|
255
|
+
Returns `None` if the update is unsuccessful.
|
|
256
|
+
|
|
257
|
+
Raises:
|
|
258
|
+
Exception: If an error occurs during the mutation execution or data retrieval.
|
|
259
|
+
"""
|
|
260
|
+
|
|
261
|
+
query = """
|
|
262
|
+
mutation IssueUpdate ($issueId: String!, $title: String!){
|
|
263
|
+
issueUpdate(
|
|
264
|
+
id: $issueId,
|
|
265
|
+
input: { title: $title}
|
|
266
|
+
) {
|
|
267
|
+
success
|
|
268
|
+
issue {
|
|
269
|
+
id
|
|
270
|
+
title
|
|
271
|
+
state {
|
|
272
|
+
id
|
|
273
|
+
name
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
"""
|
|
279
|
+
variables = {"issueId": issue_id, "title": title}
|
|
280
|
+
|
|
281
|
+
try:
|
|
282
|
+
response = self._execute_query(query, variables)
|
|
283
|
+
|
|
284
|
+
if response["issueUpdate"]["success"]:
|
|
285
|
+
issue = response["issueUpdate"]["issue"]
|
|
286
|
+
log_info(f"Issue ID {issue_id} updated successfully.")
|
|
287
|
+
return str(issue)
|
|
288
|
+
else:
|
|
289
|
+
logger.error(f"Failed to update issue ID {issue_id}. Success flag was false.")
|
|
290
|
+
return None
|
|
291
|
+
|
|
292
|
+
except Exception as e:
|
|
293
|
+
logger.error(f"Error updating issue ID {issue_id}: {e}")
|
|
294
|
+
raise
|
|
295
|
+
|
|
296
|
+
def get_user_assigned_issues(self, user_id: str) -> Optional[str]:
|
|
297
|
+
"""
|
|
298
|
+
Retrieve issues assigned to a specific user by user ID.
|
|
299
|
+
|
|
300
|
+
Args:
|
|
301
|
+
user_id (str): The unique identifier of the user for whom to retrieve assigned issues.
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
str or None: A string representing the assigned issues to user id,
|
|
305
|
+
where each issue contains issue details (e.g., `id`, `title`).
|
|
306
|
+
Returns None if the user or issues cannot be retrieved.
|
|
307
|
+
|
|
308
|
+
Raises:
|
|
309
|
+
Exception: If an error occurs while querying for the user's assigned issues.
|
|
310
|
+
"""
|
|
311
|
+
|
|
312
|
+
query = """
|
|
313
|
+
query UserAssignedIssues($userId: String!) {
|
|
314
|
+
user(id: $userId) {
|
|
315
|
+
id
|
|
316
|
+
name
|
|
317
|
+
assignedIssues {
|
|
318
|
+
nodes {
|
|
319
|
+
id
|
|
320
|
+
title
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
"""
|
|
326
|
+
variables = {"userId": user_id}
|
|
327
|
+
|
|
328
|
+
try:
|
|
329
|
+
response = self._execute_query(query, variables)
|
|
330
|
+
|
|
331
|
+
if response.get("user"):
|
|
332
|
+
user = response["user"]
|
|
333
|
+
issues = user["assignedIssues"]["nodes"]
|
|
334
|
+
log_info(f"Retrieved {len(issues)} issues assigned to user '{user['name']}' (ID: {user['id']}).")
|
|
335
|
+
return str(issues)
|
|
336
|
+
else:
|
|
337
|
+
logger.error("Failed to retrieve user or issues.")
|
|
338
|
+
return None
|
|
339
|
+
|
|
340
|
+
except Exception as e:
|
|
341
|
+
logger.error(f"Error retrieving issues for user ID {user_id}: {e}")
|
|
342
|
+
raise
|
|
343
|
+
|
|
344
|
+
def get_workflow_issues(self, workflow_id: str) -> Optional[str]:
|
|
345
|
+
"""
|
|
346
|
+
Retrieve issues within a specific workflow state by workflow ID.
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
workflow_id (str): The unique identifier of the workflow state to retrieve issues from.
|
|
350
|
+
|
|
351
|
+
Returns:
|
|
352
|
+
str or None: A string representing the issues within the specified workflow state,
|
|
353
|
+
where each issue contains details of an issue (e.g., `title`).
|
|
354
|
+
Returns None if no issues are found or if the workflow state cannot be retrieved.
|
|
355
|
+
|
|
356
|
+
Raises:
|
|
357
|
+
Exception: If an error occurs while querying issues for the specified workflow state.
|
|
358
|
+
"""
|
|
359
|
+
|
|
360
|
+
query = """
|
|
361
|
+
query WorkflowStateIssues($workflowId: String!) {
|
|
362
|
+
workflowState(id: $workflowId) {
|
|
363
|
+
issues {
|
|
364
|
+
nodes {
|
|
365
|
+
title
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
"""
|
|
371
|
+
variables = {"workflowId": workflow_id}
|
|
372
|
+
try:
|
|
373
|
+
response = self._execute_query(query, variables)
|
|
374
|
+
|
|
375
|
+
if response.get("workflowState"):
|
|
376
|
+
issues = response["workflowState"]["issues"]["nodes"]
|
|
377
|
+
log_info(f"Retrieved {len(issues)} issues in workflow state ID {workflow_id}.")
|
|
378
|
+
return str(issues)
|
|
379
|
+
else:
|
|
380
|
+
logger.error("Failed to retrieve issues for the specified workflow state.")
|
|
381
|
+
return None
|
|
382
|
+
|
|
383
|
+
except Exception as e:
|
|
384
|
+
logger.error(f"Error retrieving issues for workflow state ID {workflow_id}: {e}")
|
|
385
|
+
raise
|
|
386
|
+
|
|
387
|
+
def get_high_priority_issues(self) -> Optional[str]:
|
|
388
|
+
"""
|
|
389
|
+
Retrieve issues with a high priority (priority <= 2).
|
|
390
|
+
|
|
391
|
+
Returns:
|
|
392
|
+
str or None: A str representing high-priority issues, where it
|
|
393
|
+
contains details of an issue (e.g., `id`, `title`, `priority`).
|
|
394
|
+
Returns None if no issues are retrieved.
|
|
395
|
+
|
|
396
|
+
Raises:
|
|
397
|
+
Exception: If an error occurs during the query process.
|
|
398
|
+
"""
|
|
399
|
+
|
|
400
|
+
query = """
|
|
401
|
+
query HighPriorityIssues {
|
|
402
|
+
issues(filter: {
|
|
403
|
+
priority: { lte: 2 }
|
|
404
|
+
}) {
|
|
405
|
+
nodes {
|
|
406
|
+
id
|
|
407
|
+
title
|
|
408
|
+
priority
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
"""
|
|
413
|
+
try:
|
|
414
|
+
response = self._execute_query(query)
|
|
415
|
+
|
|
416
|
+
if response.get("issues"):
|
|
417
|
+
high_priority_issues = response["issues"]["nodes"]
|
|
418
|
+
log_info(f"Retrieved {len(high_priority_issues)} high-priority issues.")
|
|
419
|
+
return str(high_priority_issues)
|
|
420
|
+
else:
|
|
421
|
+
logger.error("Failed to retrieve high-priority issues.")
|
|
422
|
+
return None
|
|
423
|
+
|
|
424
|
+
except Exception as e:
|
|
425
|
+
logger.error(f"Error retrieving high-priority issues: {e}")
|
|
426
|
+
raise
|
agno/tools/linkup.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from os import getenv
|
|
2
|
+
from typing import Any, List, Literal, Optional
|
|
3
|
+
|
|
4
|
+
from agno.tools import Toolkit
|
|
5
|
+
from agno.utils.log import logger
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
from linkup import LinkupClient
|
|
9
|
+
except ImportError:
|
|
10
|
+
raise ImportError("`linkup-sdk` not installed. Please install using `pip install linkup-sdk`")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LinkupTools(Toolkit):
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
api_key: Optional[str] = None,
|
|
17
|
+
depth: Literal["standard", "deep"] = "standard",
|
|
18
|
+
output_type: Literal["sourcedAnswer", "searchResults"] = "searchResults",
|
|
19
|
+
enable_web_search_with_linkup: bool = True,
|
|
20
|
+
all: bool = False,
|
|
21
|
+
**kwargs,
|
|
22
|
+
):
|
|
23
|
+
self.api_key = api_key or getenv("LINKUP_API_KEY")
|
|
24
|
+
if not self.api_key:
|
|
25
|
+
logger.error("LINKUP_API_KEY not set. Please set the LINKUP_API_KEY environment variable.")
|
|
26
|
+
|
|
27
|
+
self.linkup = LinkupClient(api_key=api_key)
|
|
28
|
+
self.depth = depth
|
|
29
|
+
self.output_type = output_type
|
|
30
|
+
|
|
31
|
+
tools: List[Any] = []
|
|
32
|
+
if all or enable_web_search_with_linkup:
|
|
33
|
+
tools.append(self.web_search_with_linkup)
|
|
34
|
+
|
|
35
|
+
super().__init__(name="linkup_tools", tools=tools, **kwargs)
|
|
36
|
+
|
|
37
|
+
def web_search_with_linkup(self, query: str, depth: Optional[str] = None, output_type: Optional[str] = None) -> str:
|
|
38
|
+
"""
|
|
39
|
+
Use this function to search the web for a given query.
|
|
40
|
+
This function uses the Linkup API to provide realtime online information about the query.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
query (str): Query to search for.
|
|
44
|
+
depth (str): (deep|standard) Depth of the search. Defaults to 'standard'.
|
|
45
|
+
output_type (str): (sourcedAnswer|searchResults) Type of output. Defaults to 'searchResults'.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
str: string of results related to the query.
|
|
49
|
+
"""
|
|
50
|
+
try:
|
|
51
|
+
response = self.linkup.search(
|
|
52
|
+
query=query,
|
|
53
|
+
depth=depth or self.depth, # type: ignore
|
|
54
|
+
output_type=output_type or self.output_type, # type: ignore
|
|
55
|
+
)
|
|
56
|
+
return response
|
|
57
|
+
except Exception as e:
|
|
58
|
+
return f"Error: {str(e)}"
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from uuid import uuid4
|
|
4
|
+
|
|
5
|
+
from agno.tools import Toolkit
|
|
6
|
+
from agno.utils.log import log_debug, logger
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class LocalFileSystemTools(Toolkit):
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
target_directory: Optional[str] = None,
|
|
13
|
+
default_extension: str = "txt",
|
|
14
|
+
enable_write_file: bool = True,
|
|
15
|
+
all: bool = False,
|
|
16
|
+
**kwargs,
|
|
17
|
+
):
|
|
18
|
+
"""
|
|
19
|
+
Initialize the WriteToLocal toolkit.
|
|
20
|
+
Args:
|
|
21
|
+
target_directory (Optional[str]): Default directory to write files to. Creates if doesn't exist.
|
|
22
|
+
default_extension (str): Default file extension to use if none specified.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
self.target_directory = target_directory or str(Path.cwd())
|
|
26
|
+
self.default_extension = default_extension.lstrip(".")
|
|
27
|
+
|
|
28
|
+
target_path = Path(self.target_directory)
|
|
29
|
+
target_path.mkdir(parents=True, exist_ok=True)
|
|
30
|
+
|
|
31
|
+
tools = []
|
|
32
|
+
if all or enable_write_file:
|
|
33
|
+
tools.append(self.write_file)
|
|
34
|
+
|
|
35
|
+
super().__init__(name="write_to_local", tools=tools, **kwargs)
|
|
36
|
+
|
|
37
|
+
def write_file(
|
|
38
|
+
self,
|
|
39
|
+
content: str,
|
|
40
|
+
filename: Optional[str] = None,
|
|
41
|
+
directory: Optional[str] = None,
|
|
42
|
+
extension: Optional[str] = None,
|
|
43
|
+
) -> str:
|
|
44
|
+
"""
|
|
45
|
+
Write content to a local file.
|
|
46
|
+
Args:
|
|
47
|
+
content (str): Content to write to the file
|
|
48
|
+
filename (Optional[str]): Name of the file. Defaults to UUID if not provided
|
|
49
|
+
directory (Optional[str]): Directory to write file to. Uses target_directory if not provided
|
|
50
|
+
extension (Optional[str]): File extension. Uses default_extension if not provided
|
|
51
|
+
Returns:
|
|
52
|
+
str: Path to the created file or error message
|
|
53
|
+
"""
|
|
54
|
+
try:
|
|
55
|
+
filename = filename or str(uuid4())
|
|
56
|
+
directory = directory or self.target_directory
|
|
57
|
+
if filename and "." in filename:
|
|
58
|
+
path_obj = Path(filename)
|
|
59
|
+
filename = path_obj.stem
|
|
60
|
+
extension = extension or path_obj.suffix.lstrip(".")
|
|
61
|
+
|
|
62
|
+
log_debug(f"Writing file to local system: {filename}")
|
|
63
|
+
|
|
64
|
+
extension = (extension or self.default_extension).lstrip(".")
|
|
65
|
+
|
|
66
|
+
# Create directory if it doesn't exist
|
|
67
|
+
dir_path = Path(directory)
|
|
68
|
+
dir_path.mkdir(parents=True, exist_ok=True)
|
|
69
|
+
|
|
70
|
+
# Construct full filename with extension
|
|
71
|
+
full_filename = f"{filename}.{extension}"
|
|
72
|
+
file_path = dir_path / full_filename
|
|
73
|
+
|
|
74
|
+
file_path.write_text(content)
|
|
75
|
+
|
|
76
|
+
return f"Successfully wrote file to: {file_path}"
|
|
77
|
+
|
|
78
|
+
except Exception as e:
|
|
79
|
+
error_msg = f"Failed to write file: {str(e)}"
|
|
80
|
+
logger.error(error_msg)
|
|
81
|
+
return f"Error: {error_msg}"
|
|
82
|
+
|
|
83
|
+
def read_file(self, filename: str, directory: Optional[str] = None) -> str:
|
|
84
|
+
"""
|
|
85
|
+
Read content from a local file.
|
|
86
|
+
"""
|
|
87
|
+
file_path = Path(directory or self.target_directory) / filename
|
|
88
|
+
if not file_path.exists():
|
|
89
|
+
return f"File not found: {file_path}"
|
|
90
|
+
return file_path.read_text()
|