agno 0.1.2__py3-none-any.whl → 2.3.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agno/__init__.py +8 -0
- agno/agent/__init__.py +44 -5
- agno/agent/agent.py +10531 -2975
- agno/api/agent.py +14 -53
- agno/api/api.py +7 -46
- agno/api/evals.py +22 -0
- agno/api/os.py +17 -0
- agno/api/routes.py +6 -25
- agno/api/schemas/__init__.py +9 -0
- agno/api/schemas/agent.py +6 -9
- agno/api/schemas/evals.py +16 -0
- agno/api/schemas/os.py +14 -0
- agno/api/schemas/team.py +10 -10
- agno/api/schemas/utils.py +21 -0
- agno/api/schemas/workflows.py +16 -0
- agno/api/settings.py +53 -0
- agno/api/team.py +22 -26
- agno/api/workflow.py +28 -0
- agno/cloud/aws/base.py +214 -0
- agno/cloud/aws/s3/__init__.py +2 -0
- agno/cloud/aws/s3/api_client.py +43 -0
- agno/cloud/aws/s3/bucket.py +195 -0
- agno/cloud/aws/s3/object.py +57 -0
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/__init__.py +24 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +946 -0
- agno/db/dynamo/__init__.py +3 -0
- agno/db/dynamo/dynamo.py +2781 -0
- agno/db/dynamo/schemas.py +442 -0
- agno/db/dynamo/utils.py +743 -0
- agno/db/firestore/__init__.py +3 -0
- agno/db/firestore/firestore.py +2379 -0
- agno/db/firestore/schemas.py +181 -0
- agno/db/firestore/utils.py +376 -0
- agno/db/gcs_json/__init__.py +3 -0
- agno/db/gcs_json/gcs_json_db.py +1791 -0
- agno/db/gcs_json/utils.py +228 -0
- agno/db/in_memory/__init__.py +3 -0
- agno/db/in_memory/in_memory_db.py +1312 -0
- agno/db/in_memory/utils.py +230 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1777 -0
- agno/db/json/utils.py +230 -0
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +635 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +17 -0
- agno/db/mongo/async_mongo.py +2760 -0
- agno/db/mongo/mongo.py +2597 -0
- agno/db/mongo/schemas.py +119 -0
- agno/db/mongo/utils.py +276 -0
- agno/db/mysql/__init__.py +4 -0
- agno/db/mysql/async_mysql.py +2912 -0
- agno/db/mysql/mysql.py +2923 -0
- agno/db/mysql/schemas.py +186 -0
- agno/db/mysql/utils.py +488 -0
- agno/db/postgres/__init__.py +4 -0
- agno/db/postgres/async_postgres.py +2579 -0
- agno/db/postgres/postgres.py +2870 -0
- agno/db/postgres/schemas.py +187 -0
- agno/db/postgres/utils.py +442 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +2141 -0
- agno/db/redis/schemas.py +159 -0
- agno/db/redis/utils.py +346 -0
- agno/db/schemas/__init__.py +4 -0
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/evals.py +34 -0
- agno/db/schemas/knowledge.py +40 -0
- agno/db/schemas/memory.py +61 -0
- agno/db/singlestore/__init__.py +3 -0
- agno/db/singlestore/schemas.py +179 -0
- agno/db/singlestore/singlestore.py +2877 -0
- agno/db/singlestore/utils.py +384 -0
- agno/db/sqlite/__init__.py +4 -0
- agno/db/sqlite/async_sqlite.py +2911 -0
- agno/db/sqlite/schemas.py +181 -0
- agno/db/sqlite/sqlite.py +2908 -0
- agno/db/sqlite/utils.py +429 -0
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +334 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1908 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +118 -0
- agno/eval/__init__.py +24 -0
- agno/eval/accuracy.py +666 -276
- agno/eval/agent_as_judge.py +861 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +779 -0
- agno/eval/reliability.py +241 -62
- agno/eval/utils.py +120 -0
- agno/exceptions.py +143 -1
- agno/filters.py +354 -0
- agno/guardrails/__init__.py +6 -0
- agno/guardrails/base.py +19 -0
- agno/guardrails/openai.py +144 -0
- agno/guardrails/pii.py +94 -0
- agno/guardrails/prompt_injection.py +52 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/__init__.py +3 -0
- agno/integrations/discord/client.py +203 -0
- agno/knowledge/__init__.py +5 -1
- agno/{document → knowledge}/chunking/agentic.py +22 -14
- agno/{document → knowledge}/chunking/document.py +2 -2
- agno/{document → knowledge}/chunking/fixed.py +7 -6
- agno/knowledge/chunking/markdown.py +151 -0
- agno/{document → knowledge}/chunking/recursive.py +15 -3
- agno/knowledge/chunking/row.py +39 -0
- agno/knowledge/chunking/semantic.py +91 -0
- agno/knowledge/chunking/strategy.py +165 -0
- agno/knowledge/content.py +74 -0
- agno/knowledge/document/__init__.py +5 -0
- agno/{document → knowledge/document}/base.py +12 -2
- agno/knowledge/embedder/__init__.py +5 -0
- agno/knowledge/embedder/aws_bedrock.py +343 -0
- agno/knowledge/embedder/azure_openai.py +210 -0
- agno/{embedder → knowledge/embedder}/base.py +8 -0
- agno/knowledge/embedder/cohere.py +323 -0
- agno/knowledge/embedder/fastembed.py +62 -0
- agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
- agno/knowledge/embedder/google.py +258 -0
- agno/knowledge/embedder/huggingface.py +94 -0
- agno/knowledge/embedder/jina.py +182 -0
- agno/knowledge/embedder/langdb.py +22 -0
- agno/knowledge/embedder/mistral.py +206 -0
- agno/knowledge/embedder/nebius.py +13 -0
- agno/knowledge/embedder/ollama.py +154 -0
- agno/knowledge/embedder/openai.py +195 -0
- agno/knowledge/embedder/sentence_transformer.py +63 -0
- agno/{embedder → knowledge/embedder}/together.py +1 -1
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +165 -0
- agno/knowledge/knowledge.py +3006 -0
- agno/knowledge/reader/__init__.py +7 -0
- agno/knowledge/reader/arxiv_reader.py +81 -0
- agno/knowledge/reader/base.py +95 -0
- agno/knowledge/reader/csv_reader.py +164 -0
- agno/knowledge/reader/docx_reader.py +82 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/firecrawl_reader.py +201 -0
- agno/knowledge/reader/json_reader.py +88 -0
- agno/knowledge/reader/markdown_reader.py +137 -0
- agno/knowledge/reader/pdf_reader.py +431 -0
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +313 -0
- agno/knowledge/reader/s3_reader.py +89 -0
- agno/knowledge/reader/tavily_reader.py +193 -0
- agno/knowledge/reader/text_reader.py +127 -0
- agno/knowledge/reader/web_search_reader.py +325 -0
- agno/knowledge/reader/website_reader.py +455 -0
- agno/knowledge/reader/wikipedia_reader.py +91 -0
- agno/knowledge/reader/youtube_reader.py +78 -0
- agno/knowledge/remote_content/remote_content.py +88 -0
- agno/knowledge/reranker/__init__.py +3 -0
- agno/{reranker → knowledge/reranker}/base.py +1 -1
- agno/{reranker → knowledge/reranker}/cohere.py +2 -2
- agno/knowledge/reranker/infinity.py +195 -0
- agno/knowledge/reranker/sentence_transformer.py +54 -0
- agno/knowledge/types.py +39 -0
- agno/knowledge/utils.py +234 -0
- agno/media.py +439 -95
- agno/memory/__init__.py +16 -3
- agno/memory/manager.py +1474 -123
- agno/memory/strategies/__init__.py +15 -0
- agno/memory/strategies/base.py +66 -0
- agno/memory/strategies/summarize.py +196 -0
- agno/memory/strategies/types.py +37 -0
- agno/models/aimlapi/__init__.py +5 -0
- agno/models/aimlapi/aimlapi.py +62 -0
- agno/models/anthropic/__init__.py +4 -0
- agno/models/anthropic/claude.py +960 -496
- agno/models/aws/__init__.py +15 -0
- agno/models/aws/bedrock.py +686 -451
- agno/models/aws/claude.py +190 -183
- agno/models/azure/__init__.py +18 -1
- agno/models/azure/ai_foundry.py +489 -0
- agno/models/azure/openai_chat.py +89 -40
- agno/models/base.py +2477 -550
- agno/models/cerebras/__init__.py +12 -0
- agno/models/cerebras/cerebras.py +565 -0
- agno/models/cerebras/cerebras_openai.py +131 -0
- agno/models/cohere/__init__.py +4 -0
- agno/models/cohere/chat.py +306 -492
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +74 -0
- agno/models/dashscope/__init__.py +5 -0
- agno/models/dashscope/dashscope.py +90 -0
- agno/models/deepinfra/__init__.py +5 -0
- agno/models/deepinfra/deepinfra.py +45 -0
- agno/models/deepseek/__init__.py +4 -0
- agno/models/deepseek/deepseek.py +110 -9
- agno/models/fireworks/__init__.py +4 -0
- agno/models/fireworks/fireworks.py +19 -22
- agno/models/google/__init__.py +3 -7
- agno/models/google/gemini.py +1717 -662
- agno/models/google/utils.py +22 -0
- agno/models/groq/__init__.py +4 -0
- agno/models/groq/groq.py +391 -666
- agno/models/huggingface/__init__.py +4 -0
- agno/models/huggingface/huggingface.py +266 -538
- agno/models/ibm/__init__.py +5 -0
- agno/models/ibm/watsonx.py +432 -0
- agno/models/internlm/__init__.py +3 -0
- agno/models/internlm/internlm.py +20 -3
- agno/models/langdb/__init__.py +1 -0
- agno/models/langdb/langdb.py +60 -0
- agno/models/litellm/__init__.py +14 -0
- agno/models/litellm/chat.py +503 -0
- agno/models/litellm/litellm_openai.py +42 -0
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/lmstudio/__init__.py +5 -0
- agno/models/lmstudio/lmstudio.py +25 -0
- agno/models/message.py +361 -39
- agno/models/meta/__init__.py +12 -0
- agno/models/meta/llama.py +502 -0
- agno/models/meta/llama_openai.py +79 -0
- agno/models/metrics.py +120 -0
- agno/models/mistral/__init__.py +4 -0
- agno/models/mistral/mistral.py +293 -393
- agno/models/nebius/__init__.py +3 -0
- agno/models/nebius/nebius.py +53 -0
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/__init__.py +4 -0
- agno/models/nvidia/nvidia.py +22 -3
- agno/models/ollama/__init__.py +4 -2
- agno/models/ollama/chat.py +257 -492
- agno/models/openai/__init__.py +7 -0
- agno/models/openai/chat.py +725 -770
- agno/models/openai/like.py +16 -2
- agno/models/openai/responses.py +1121 -0
- agno/models/openrouter/__init__.py +4 -0
- agno/models/openrouter/openrouter.py +62 -5
- agno/models/perplexity/__init__.py +5 -0
- agno/models/perplexity/perplexity.py +203 -0
- agno/models/portkey/__init__.py +3 -0
- agno/models/portkey/portkey.py +82 -0
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +69 -0
- agno/models/response.py +177 -7
- agno/models/sambanova/__init__.py +4 -0
- agno/models/sambanova/sambanova.py +23 -4
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +42 -0
- agno/models/together/__init__.py +4 -0
- agno/models/together/together.py +21 -164
- agno/models/utils.py +266 -0
- agno/models/vercel/__init__.py +3 -0
- agno/models/vercel/v0.py +43 -0
- agno/models/vertexai/__init__.py +0 -1
- agno/models/vertexai/claude.py +190 -0
- agno/models/vllm/__init__.py +3 -0
- agno/models/vllm/vllm.py +83 -0
- agno/models/xai/__init__.py +2 -0
- agno/models/xai/xai.py +111 -7
- agno/os/__init__.py +3 -0
- agno/os/app.py +1027 -0
- agno/os/auth.py +244 -0
- agno/os/config.py +126 -0
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/a2a/__init__.py +3 -0
- agno/os/interfaces/a2a/a2a.py +42 -0
- agno/os/interfaces/a2a/router.py +249 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/__init__.py +3 -0
- agno/os/interfaces/agui/agui.py +47 -0
- agno/os/interfaces/agui/router.py +147 -0
- agno/os/interfaces/agui/utils.py +574 -0
- agno/os/interfaces/base.py +25 -0
- agno/os/interfaces/slack/__init__.py +3 -0
- agno/os/interfaces/slack/router.py +148 -0
- agno/os/interfaces/slack/security.py +30 -0
- agno/os/interfaces/slack/slack.py +47 -0
- agno/os/interfaces/whatsapp/__init__.py +3 -0
- agno/os/interfaces/whatsapp/router.py +210 -0
- agno/os/interfaces/whatsapp/security.py +55 -0
- agno/os/interfaces/whatsapp/whatsapp.py +36 -0
- agno/os/mcp.py +293 -0
- agno/os/middleware/__init__.py +9 -0
- agno/os/middleware/jwt.py +797 -0
- agno/os/router.py +258 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +599 -0
- agno/os/routers/agents/schema.py +261 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +450 -0
- agno/os/routers/evals/schemas.py +174 -0
- agno/os/routers/evals/utils.py +231 -0
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/__init__.py +3 -0
- agno/os/routers/knowledge/knowledge.py +1008 -0
- agno/os/routers/knowledge/schemas.py +178 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +661 -0
- agno/os/routers/memory/schemas.py +88 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +190 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +997 -0
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +512 -0
- agno/os/routers/teams/schema.py +257 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +499 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +624 -0
- agno/os/routers/workflows/schema.py +75 -0
- agno/os/schema.py +534 -0
- agno/os/scopes.py +469 -0
- agno/{playground → os}/settings.py +7 -15
- agno/os/utils.py +973 -0
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +67 -0
- agno/reasoning/deepseek.py +63 -0
- agno/reasoning/default.py +97 -0
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +71 -0
- agno/reasoning/helpers.py +24 -1
- agno/reasoning/ollama.py +67 -0
- agno/reasoning/openai.py +86 -0
- agno/reasoning/step.py +2 -1
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +822 -0
- agno/run/base.py +247 -0
- agno/run/cancel.py +81 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +767 -0
- agno/run/workflow.py +708 -0
- agno/session/__init__.py +10 -0
- agno/session/agent.py +260 -0
- agno/session/summary.py +265 -0
- agno/session/team.py +342 -0
- agno/session/workflow.py +501 -0
- agno/table.py +10 -0
- agno/team/__init__.py +37 -0
- agno/team/team.py +9536 -0
- agno/tools/__init__.py +7 -0
- agno/tools/agentql.py +120 -0
- agno/tools/airflow.py +22 -12
- agno/tools/api.py +122 -0
- agno/tools/apify.py +276 -83
- agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
- agno/tools/aws_lambda.py +28 -7
- agno/tools/aws_ses.py +66 -0
- agno/tools/baidusearch.py +11 -4
- agno/tools/bitbucket.py +292 -0
- agno/tools/brandfetch.py +213 -0
- agno/tools/bravesearch.py +106 -0
- agno/tools/brightdata.py +367 -0
- agno/tools/browserbase.py +209 -0
- agno/tools/calcom.py +32 -23
- agno/tools/calculator.py +24 -37
- agno/tools/cartesia.py +187 -0
- agno/tools/{clickup_tool.py → clickup.py} +17 -28
- agno/tools/confluence.py +91 -26
- agno/tools/crawl4ai.py +139 -43
- agno/tools/csv_toolkit.py +28 -22
- agno/tools/dalle.py +36 -22
- agno/tools/daytona.py +475 -0
- agno/tools/decorator.py +169 -14
- agno/tools/desi_vocal.py +23 -11
- agno/tools/discord.py +32 -29
- agno/tools/docker.py +716 -0
- agno/tools/duckdb.py +76 -81
- agno/tools/duckduckgo.py +43 -40
- agno/tools/e2b.py +703 -0
- agno/tools/eleven_labs.py +65 -54
- agno/tools/email.py +13 -5
- agno/tools/evm.py +129 -0
- agno/tools/exa.py +324 -42
- agno/tools/fal.py +39 -35
- agno/tools/file.py +196 -30
- agno/tools/file_generation.py +356 -0
- agno/tools/financial_datasets.py +288 -0
- agno/tools/firecrawl.py +108 -33
- agno/tools/function.py +960 -122
- agno/tools/giphy.py +34 -12
- agno/tools/github.py +1294 -97
- agno/tools/gmail.py +922 -0
- agno/tools/google_bigquery.py +117 -0
- agno/tools/google_drive.py +271 -0
- agno/tools/google_maps.py +253 -0
- agno/tools/googlecalendar.py +607 -107
- agno/tools/googlesheets.py +377 -0
- agno/tools/hackernews.py +20 -12
- agno/tools/jina.py +24 -14
- agno/tools/jira.py +48 -19
- agno/tools/knowledge.py +218 -0
- agno/tools/linear.py +82 -43
- agno/tools/linkup.py +58 -0
- agno/tools/local_file_system.py +15 -7
- agno/tools/lumalab.py +41 -26
- agno/tools/mcp/__init__.py +10 -0
- agno/tools/mcp/mcp.py +331 -0
- agno/tools/mcp/multi_mcp.py +347 -0
- agno/tools/mcp/params.py +24 -0
- agno/tools/mcp_toolbox.py +284 -0
- agno/tools/mem0.py +193 -0
- agno/tools/memory.py +419 -0
- agno/tools/mlx_transcribe.py +11 -9
- agno/tools/models/azure_openai.py +190 -0
- agno/tools/models/gemini.py +203 -0
- agno/tools/models/groq.py +158 -0
- agno/tools/models/morph.py +186 -0
- agno/tools/models/nebius.py +124 -0
- agno/tools/models_labs.py +163 -82
- agno/tools/moviepy_video.py +18 -13
- agno/tools/nano_banana.py +151 -0
- agno/tools/neo4j.py +134 -0
- agno/tools/newspaper.py +15 -4
- agno/tools/newspaper4k.py +19 -6
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +181 -17
- agno/tools/openbb.py +27 -20
- agno/tools/opencv.py +321 -0
- agno/tools/openweather.py +233 -0
- agno/tools/oxylabs.py +385 -0
- agno/tools/pandas.py +25 -15
- agno/tools/parallel.py +314 -0
- agno/tools/postgres.py +238 -185
- agno/tools/pubmed.py +125 -13
- agno/tools/python.py +48 -35
- agno/tools/reasoning.py +283 -0
- agno/tools/reddit.py +207 -29
- agno/tools/redshift.py +406 -0
- agno/tools/replicate.py +69 -26
- agno/tools/resend.py +11 -6
- agno/tools/scrapegraph.py +179 -19
- agno/tools/searxng.py +23 -31
- agno/tools/serpapi.py +15 -10
- agno/tools/serper.py +255 -0
- agno/tools/shell.py +23 -12
- agno/tools/shopify.py +1519 -0
- agno/tools/slack.py +56 -14
- agno/tools/sleep.py +8 -6
- agno/tools/spider.py +35 -11
- agno/tools/spotify.py +919 -0
- agno/tools/sql.py +34 -19
- agno/tools/tavily.py +158 -8
- agno/tools/telegram.py +18 -8
- agno/tools/todoist.py +218 -0
- agno/tools/toolkit.py +134 -9
- agno/tools/trafilatura.py +388 -0
- agno/tools/trello.py +25 -28
- agno/tools/twilio.py +18 -9
- agno/tools/user_control_flow.py +78 -0
- agno/tools/valyu.py +228 -0
- agno/tools/visualization.py +467 -0
- agno/tools/webbrowser.py +28 -0
- agno/tools/webex.py +76 -0
- agno/tools/website.py +23 -19
- agno/tools/webtools.py +45 -0
- agno/tools/whatsapp.py +286 -0
- agno/tools/wikipedia.py +28 -19
- agno/tools/workflow.py +285 -0
- agno/tools/{twitter.py → x.py} +142 -46
- agno/tools/yfinance.py +41 -39
- agno/tools/youtube.py +34 -17
- agno/tools/zendesk.py +15 -5
- agno/tools/zep.py +454 -0
- agno/tools/zoom.py +86 -37
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +157 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +111 -0
- agno/utils/agent.py +938 -0
- agno/utils/audio.py +37 -1
- agno/utils/certs.py +27 -0
- agno/utils/code_execution.py +11 -0
- agno/utils/common.py +103 -20
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +700 -0
- agno/utils/functions.py +107 -37
- agno/utils/gemini.py +426 -0
- agno/utils/hooks.py +171 -0
- agno/utils/http.py +185 -0
- agno/utils/json_schema.py +159 -37
- agno/utils/knowledge.py +36 -0
- agno/utils/location.py +19 -0
- agno/utils/log.py +221 -8
- agno/utils/mcp.py +214 -0
- agno/utils/media.py +335 -14
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +77 -2
- agno/utils/models/ai_foundry.py +50 -0
- agno/utils/models/claude.py +373 -0
- agno/utils/models/cohere.py +94 -0
- agno/utils/models/llama.py +85 -0
- agno/utils/models/mistral.py +100 -0
- agno/utils/models/openai_responses.py +140 -0
- agno/utils/models/schema_utils.py +153 -0
- agno/utils/models/watsonx.py +41 -0
- agno/utils/openai.py +257 -0
- agno/utils/pickle.py +1 -1
- agno/utils/pprint.py +124 -8
- agno/utils/print_response/agent.py +930 -0
- agno/utils/print_response/team.py +1914 -0
- agno/utils/print_response/workflow.py +1668 -0
- agno/utils/prompts.py +111 -0
- agno/utils/reasoning.py +108 -0
- agno/utils/response.py +163 -0
- agno/utils/serialize.py +32 -0
- agno/utils/shell.py +4 -4
- agno/utils/streamlit.py +487 -0
- agno/utils/string.py +204 -51
- agno/utils/team.py +139 -0
- agno/utils/timer.py +9 -2
- agno/utils/tokens.py +657 -0
- agno/utils/tools.py +19 -1
- agno/utils/whatsapp.py +305 -0
- agno/utils/yaml_io.py +3 -3
- agno/vectordb/__init__.py +2 -0
- agno/vectordb/base.py +87 -9
- agno/vectordb/cassandra/__init__.py +5 -1
- agno/vectordb/cassandra/cassandra.py +383 -27
- agno/vectordb/chroma/__init__.py +4 -0
- agno/vectordb/chroma/chromadb.py +748 -83
- agno/vectordb/clickhouse/__init__.py +7 -1
- agno/vectordb/clickhouse/clickhousedb.py +554 -53
- agno/vectordb/couchbase/__init__.py +3 -0
- agno/vectordb/couchbase/couchbase.py +1446 -0
- agno/vectordb/lancedb/__init__.py +5 -0
- agno/vectordb/lancedb/lance_db.py +730 -98
- agno/vectordb/langchaindb/__init__.py +5 -0
- agno/vectordb/langchaindb/langchaindb.py +163 -0
- agno/vectordb/lightrag/__init__.py +5 -0
- agno/vectordb/lightrag/lightrag.py +388 -0
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +166 -0
- agno/vectordb/milvus/__init__.py +3 -0
- agno/vectordb/milvus/milvus.py +966 -78
- agno/vectordb/mongodb/__init__.py +9 -1
- agno/vectordb/mongodb/mongodb.py +1175 -172
- agno/vectordb/pgvector/__init__.py +8 -0
- agno/vectordb/pgvector/pgvector.py +599 -115
- agno/vectordb/pineconedb/__init__.py +5 -1
- agno/vectordb/pineconedb/pineconedb.py +406 -43
- agno/vectordb/qdrant/__init__.py +4 -0
- agno/vectordb/qdrant/qdrant.py +914 -61
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +682 -0
- agno/vectordb/singlestore/__init__.py +8 -1
- agno/vectordb/singlestore/singlestore.py +771 -0
- agno/vectordb/surrealdb/__init__.py +3 -0
- agno/vectordb/surrealdb/surrealdb.py +663 -0
- agno/vectordb/upstashdb/__init__.py +5 -0
- agno/vectordb/upstashdb/upstashdb.py +718 -0
- agno/vectordb/weaviate/__init__.py +8 -0
- agno/vectordb/weaviate/index.py +15 -0
- agno/vectordb/weaviate/weaviate.py +1009 -0
- agno/workflow/__init__.py +23 -1
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +759 -0
- agno/workflow/loop.py +756 -0
- agno/workflow/parallel.py +853 -0
- agno/workflow/router.py +723 -0
- agno/workflow/step.py +1564 -0
- agno/workflow/steps.py +613 -0
- agno/workflow/types.py +556 -0
- agno/workflow/workflow.py +4327 -514
- agno-2.3.13.dist-info/METADATA +639 -0
- agno-2.3.13.dist-info/RECORD +613 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
- agno-2.3.13.dist-info/licenses/LICENSE +201 -0
- agno/api/playground.py +0 -91
- agno/api/schemas/playground.py +0 -22
- agno/api/schemas/user.py +0 -22
- agno/api/schemas/workspace.py +0 -46
- agno/api/user.py +0 -160
- agno/api/workspace.py +0 -151
- agno/cli/auth_server.py +0 -118
- agno/cli/config.py +0 -275
- agno/cli/console.py +0 -88
- agno/cli/credentials.py +0 -23
- agno/cli/entrypoint.py +0 -571
- agno/cli/operator.py +0 -355
- agno/cli/settings.py +0 -85
- agno/cli/ws/ws_cli.py +0 -817
- agno/constants.py +0 -13
- agno/document/__init__.py +0 -1
- agno/document/chunking/semantic.py +0 -47
- agno/document/chunking/strategy.py +0 -31
- agno/document/reader/__init__.py +0 -1
- agno/document/reader/arxiv_reader.py +0 -41
- agno/document/reader/base.py +0 -22
- agno/document/reader/csv_reader.py +0 -84
- agno/document/reader/docx_reader.py +0 -46
- agno/document/reader/firecrawl_reader.py +0 -99
- agno/document/reader/json_reader.py +0 -43
- agno/document/reader/pdf_reader.py +0 -219
- agno/document/reader/s3/pdf_reader.py +0 -46
- agno/document/reader/s3/text_reader.py +0 -51
- agno/document/reader/text_reader.py +0 -41
- agno/document/reader/website_reader.py +0 -175
- agno/document/reader/youtube_reader.py +0 -50
- agno/embedder/__init__.py +0 -1
- agno/embedder/azure_openai.py +0 -86
- agno/embedder/cohere.py +0 -72
- agno/embedder/fastembed.py +0 -37
- agno/embedder/google.py +0 -73
- agno/embedder/huggingface.py +0 -54
- agno/embedder/mistral.py +0 -80
- agno/embedder/ollama.py +0 -57
- agno/embedder/openai.py +0 -74
- agno/embedder/sentence_transformer.py +0 -38
- agno/embedder/voyageai.py +0 -64
- agno/eval/perf.py +0 -201
- agno/file/__init__.py +0 -1
- agno/file/file.py +0 -16
- agno/file/local/csv.py +0 -32
- agno/file/local/txt.py +0 -19
- agno/infra/app.py +0 -240
- agno/infra/base.py +0 -144
- agno/infra/context.py +0 -20
- agno/infra/db_app.py +0 -52
- agno/infra/resource.py +0 -205
- agno/infra/resources.py +0 -55
- agno/knowledge/agent.py +0 -230
- agno/knowledge/arxiv.py +0 -22
- agno/knowledge/combined.py +0 -22
- agno/knowledge/csv.py +0 -28
- agno/knowledge/csv_url.py +0 -19
- agno/knowledge/document.py +0 -20
- agno/knowledge/docx.py +0 -30
- agno/knowledge/json.py +0 -28
- agno/knowledge/langchain.py +0 -71
- agno/knowledge/llamaindex.py +0 -66
- agno/knowledge/pdf.py +0 -28
- agno/knowledge/pdf_url.py +0 -26
- agno/knowledge/s3/base.py +0 -60
- agno/knowledge/s3/pdf.py +0 -21
- agno/knowledge/s3/text.py +0 -23
- agno/knowledge/text.py +0 -30
- agno/knowledge/website.py +0 -88
- agno/knowledge/wikipedia.py +0 -31
- agno/knowledge/youtube.py +0 -22
- agno/memory/agent.py +0 -392
- agno/memory/classifier.py +0 -104
- agno/memory/db/__init__.py +0 -1
- agno/memory/db/base.py +0 -42
- agno/memory/db/mongodb.py +0 -189
- agno/memory/db/postgres.py +0 -203
- agno/memory/db/sqlite.py +0 -193
- agno/memory/memory.py +0 -15
- agno/memory/row.py +0 -36
- agno/memory/summarizer.py +0 -192
- agno/memory/summary.py +0 -19
- agno/memory/workflow.py +0 -38
- agno/models/google/gemini_openai.py +0 -26
- agno/models/ollama/hermes.py +0 -221
- agno/models/ollama/tools.py +0 -362
- agno/models/vertexai/gemini.py +0 -595
- agno/playground/__init__.py +0 -3
- agno/playground/async_router.py +0 -421
- agno/playground/deploy.py +0 -249
- agno/playground/operator.py +0 -92
- agno/playground/playground.py +0 -91
- agno/playground/schemas.py +0 -76
- agno/playground/serve.py +0 -55
- agno/playground/sync_router.py +0 -405
- agno/reasoning/agent.py +0 -68
- agno/run/response.py +0 -112
- agno/storage/agent/__init__.py +0 -0
- agno/storage/agent/base.py +0 -38
- agno/storage/agent/dynamodb.py +0 -350
- agno/storage/agent/json.py +0 -92
- agno/storage/agent/mongodb.py +0 -228
- agno/storage/agent/postgres.py +0 -367
- agno/storage/agent/session.py +0 -79
- agno/storage/agent/singlestore.py +0 -303
- agno/storage/agent/sqlite.py +0 -357
- agno/storage/agent/yaml.py +0 -93
- agno/storage/workflow/__init__.py +0 -0
- agno/storage/workflow/base.py +0 -40
- agno/storage/workflow/mongodb.py +0 -233
- agno/storage/workflow/postgres.py +0 -366
- agno/storage/workflow/session.py +0 -60
- agno/storage/workflow/sqlite.py +0 -359
- agno/tools/googlesearch.py +0 -88
- agno/utils/defaults.py +0 -57
- agno/utils/filesystem.py +0 -39
- agno/utils/git.py +0 -52
- agno/utils/json_io.py +0 -30
- agno/utils/load_env.py +0 -19
- agno/utils/py_io.py +0 -19
- agno/utils/pyproject.py +0 -18
- agno/utils/resource_filter.py +0 -31
- agno/vectordb/singlestore/s2vectordb.py +0 -390
- agno/vectordb/singlestore/s2vectordb2.py +0 -355
- agno/workspace/__init__.py +0 -0
- agno/workspace/config.py +0 -325
- agno/workspace/enums.py +0 -6
- agno/workspace/helpers.py +0 -48
- agno/workspace/operator.py +0 -758
- agno/workspace/settings.py +0 -63
- agno-0.1.2.dist-info/LICENSE +0 -375
- agno-0.1.2.dist-info/METADATA +0 -502
- agno-0.1.2.dist-info/RECORD +0 -352
- agno-0.1.2.dist-info/entry_points.txt +0 -3
- /agno/{cli → db/migrations}/__init__.py +0 -0
- /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
- /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
- /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
- /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
- /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
- /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
- /agno/{reranker → utils/models}/__init__.py +0 -0
- /agno/{storage → utils/print_response}/__init__.py +0 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
agno/tools/bitbucket.py
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import json
|
|
3
|
+
from os import getenv
|
|
4
|
+
from typing import Any, Dict, Optional, Union
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
from agno.tools import Toolkit
|
|
9
|
+
from agno.utils.log import logger
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BitbucketTools(Toolkit):
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
server_url: str = "api.bitbucket.org",
|
|
16
|
+
username: Optional[str] = None,
|
|
17
|
+
password: Optional[str] = None,
|
|
18
|
+
token: Optional[str] = None,
|
|
19
|
+
workspace: Optional[str] = None,
|
|
20
|
+
repo_slug: Optional[str] = None,
|
|
21
|
+
api_version: str = "2.0",
|
|
22
|
+
**kwargs,
|
|
23
|
+
):
|
|
24
|
+
self.username = username or getenv("BITBUCKET_USERNAME")
|
|
25
|
+
self.password = password or getenv("BITBUCKET_PASSWORD")
|
|
26
|
+
self.token = token or getenv("BITBUCKET_TOKEN")
|
|
27
|
+
self.auth_password = self.token or self.password
|
|
28
|
+
self.server_url = server_url or "api.bitbucket.org"
|
|
29
|
+
self.api_version = api_version or "2.0"
|
|
30
|
+
self.base_url = (
|
|
31
|
+
f"https://{self.server_url}/{api_version}"
|
|
32
|
+
if not self.server_url.startswith(("http://", "https://"))
|
|
33
|
+
else f"{self.server_url}/{api_version}"
|
|
34
|
+
)
|
|
35
|
+
self.workspace = workspace
|
|
36
|
+
self.repo_slug = repo_slug
|
|
37
|
+
|
|
38
|
+
if not (self.username and self.auth_password):
|
|
39
|
+
raise ValueError("Username and password or token are required")
|
|
40
|
+
|
|
41
|
+
if not self.workspace:
|
|
42
|
+
raise ValueError("Workspace is required")
|
|
43
|
+
if not self.repo_slug:
|
|
44
|
+
raise ValueError("Repo slug is required")
|
|
45
|
+
|
|
46
|
+
self.headers = {"Accept": "application/json", "Authorization": f"Basic {self._generate_access_token()}"}
|
|
47
|
+
|
|
48
|
+
super().__init__(
|
|
49
|
+
name="bitbucket",
|
|
50
|
+
tools=[
|
|
51
|
+
self.list_repositories,
|
|
52
|
+
self.get_repository_details,
|
|
53
|
+
self.create_repository,
|
|
54
|
+
self.list_repository_commits,
|
|
55
|
+
self.list_all_pull_requests,
|
|
56
|
+
self.get_pull_request_details,
|
|
57
|
+
self.get_pull_request_changes,
|
|
58
|
+
self.list_issues,
|
|
59
|
+
],
|
|
60
|
+
**kwargs,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def _generate_access_token(self) -> str:
|
|
64
|
+
auth_str = f"{self.username}:{self.auth_password}"
|
|
65
|
+
auth_bytes = auth_str.encode("ascii")
|
|
66
|
+
auth_base64 = base64.b64encode(auth_bytes).decode("ascii")
|
|
67
|
+
return auth_base64
|
|
68
|
+
|
|
69
|
+
def _make_request(
|
|
70
|
+
self,
|
|
71
|
+
method: str,
|
|
72
|
+
endpoint: str,
|
|
73
|
+
params: Optional[Dict[str, Any]] = None,
|
|
74
|
+
data: Optional[Dict[str, Any]] = None,
|
|
75
|
+
) -> Union[str, Dict[str, Any]]:
|
|
76
|
+
url = f"{self.base_url}{endpoint}"
|
|
77
|
+
response = requests.request(method, url, headers=self.headers, json=data, params=params)
|
|
78
|
+
response.raise_for_status()
|
|
79
|
+
encoding_type = response.headers.get("Content-Type", "application/json")
|
|
80
|
+
if encoding_type.startswith("application/json"):
|
|
81
|
+
return response.json() if response.text else {}
|
|
82
|
+
elif encoding_type == "text/plain":
|
|
83
|
+
return response.text
|
|
84
|
+
|
|
85
|
+
logger.warning(f"Unsupported content type: {encoding_type}")
|
|
86
|
+
return {}
|
|
87
|
+
|
|
88
|
+
def list_repositories(self, count: int = 10) -> str:
|
|
89
|
+
"""
|
|
90
|
+
Get all repositories in the workspace.
|
|
91
|
+
Args:
|
|
92
|
+
count (int, optional): The number of repositories to retrieve
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
str: A JSON string containing repository list.
|
|
96
|
+
"""
|
|
97
|
+
try:
|
|
98
|
+
# Limit count to maximum of 50
|
|
99
|
+
count = min(count, 50)
|
|
100
|
+
|
|
101
|
+
# Use count directly as pagelen for simplicity, max out at 50 per our limit
|
|
102
|
+
pagelen = min(count, 50)
|
|
103
|
+
params = {"page": 1, "pagelen": pagelen}
|
|
104
|
+
|
|
105
|
+
repo = self._make_request("GET", f"/repositories/{self.workspace}", params=params)
|
|
106
|
+
|
|
107
|
+
return json.dumps(repo, indent=2)
|
|
108
|
+
except Exception as e:
|
|
109
|
+
logger.error(f"Error retrieving repository list for workspace {self.workspace}: {str(e)}")
|
|
110
|
+
return json.dumps({"error": str(e)})
|
|
111
|
+
|
|
112
|
+
def get_repository_details(self) -> str:
|
|
113
|
+
"""
|
|
114
|
+
Retrieves repository information.
|
|
115
|
+
API Docs: https://developer.atlassian.com/cloud/bitbucket/rest/api-group-repositories/#api-repositories-workspace-repo-slug-get
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
str: A JSON string containing repository information.
|
|
119
|
+
"""
|
|
120
|
+
try:
|
|
121
|
+
repo = self._make_request("GET", f"/repositories/{self.workspace}/{self.repo_slug}")
|
|
122
|
+
return json.dumps(repo, indent=2)
|
|
123
|
+
except Exception as e:
|
|
124
|
+
logger.error(f"Error retrieving repository information for {self.repo_slug}: {str(e)}")
|
|
125
|
+
return json.dumps({"error": str(e)})
|
|
126
|
+
|
|
127
|
+
def create_repository(
|
|
128
|
+
self,
|
|
129
|
+
name: str,
|
|
130
|
+
project: Optional[str] = None,
|
|
131
|
+
is_private: bool = False,
|
|
132
|
+
description: Optional[str] = None,
|
|
133
|
+
language: Optional[str] = None,
|
|
134
|
+
has_issues: bool = False,
|
|
135
|
+
has_wiki: bool = False,
|
|
136
|
+
) -> str:
|
|
137
|
+
"""
|
|
138
|
+
Creates a new repository in Bitbucket for the given workspace.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
name (str): The name of the new repository.
|
|
142
|
+
project (str, optional): The key of the project to create the repository in.
|
|
143
|
+
is_private (bool, optional): Whether the repository is private.
|
|
144
|
+
description (str, optional): A short description of the repository.
|
|
145
|
+
language (str, optional): The primary language of the repository
|
|
146
|
+
has_issues (bool, optional): Whether the repository has issues enabled.
|
|
147
|
+
has_wiki (bool, optional): Whether the repository has a wiki enabled.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
str: A JSON string containing repository information.
|
|
151
|
+
"""
|
|
152
|
+
try:
|
|
153
|
+
payload: Dict[str, Any] = {
|
|
154
|
+
"name": name,
|
|
155
|
+
"scm": "git",
|
|
156
|
+
"is_private": is_private,
|
|
157
|
+
"description": description,
|
|
158
|
+
"language": language,
|
|
159
|
+
"has_issues": has_issues,
|
|
160
|
+
"has_wiki": has_wiki,
|
|
161
|
+
}
|
|
162
|
+
if project:
|
|
163
|
+
payload["project"] = {"key": project}
|
|
164
|
+
repo = self._make_request("POST", f"/repositories/{self.workspace}/{self.repo_slug}", data=payload)
|
|
165
|
+
return json.dumps(repo, indent=2)
|
|
166
|
+
except Exception as e:
|
|
167
|
+
logger.error(f"Error creating repository {self.repo_slug} for {self.workspace}: {str(e)}")
|
|
168
|
+
return json.dumps({"error": str(e)})
|
|
169
|
+
|
|
170
|
+
def list_repository_commits(self, count: int = 10) -> str:
|
|
171
|
+
"""
|
|
172
|
+
Retrieves all commits in a repository.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
count (int, optional): The number of commits to retrieve. Defaults to 10. Maximum 50.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
str: A JSON string containing all commits.
|
|
179
|
+
"""
|
|
180
|
+
try:
|
|
181
|
+
count = min(count, 50)
|
|
182
|
+
params = {"pagelen": count}
|
|
183
|
+
|
|
184
|
+
commits = self._make_request(
|
|
185
|
+
"GET", f"/repositories/{self.workspace}/{self.repo_slug}/commits", params=params
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
if isinstance(commits, dict) and commits.get("next"):
|
|
189
|
+
collected_commits = commits.get("values", [])
|
|
190
|
+
|
|
191
|
+
while len(collected_commits) < count and isinstance(commits, dict) and commits.get("next"):
|
|
192
|
+
next_url = commits["next"] # type: ignore
|
|
193
|
+
query_param = next_url.split("?")[1] if "?" in next_url else ""
|
|
194
|
+
commits = self._make_request(
|
|
195
|
+
"GET", f"/repositories/{self.workspace}/{self.repo_slug}/commits?{query_param}"
|
|
196
|
+
)
|
|
197
|
+
if isinstance(commits, dict):
|
|
198
|
+
collected_commits.extend(commits.get("values", []))
|
|
199
|
+
|
|
200
|
+
if isinstance(commits, dict):
|
|
201
|
+
commits["values"] = collected_commits[:count]
|
|
202
|
+
|
|
203
|
+
return json.dumps(commits, indent=2)
|
|
204
|
+
except Exception as e:
|
|
205
|
+
logger.error(f"Error retrieving commits for {self.repo_slug}: {str(e)}")
|
|
206
|
+
return json.dumps({"error": str(e)})
|
|
207
|
+
|
|
208
|
+
def list_all_pull_requests(self, state: str = "OPEN") -> str:
|
|
209
|
+
"""
|
|
210
|
+
Retrieves all pull requests for a repository.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
state (str, optional): The state of the pull requests to retrieve.
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
str: A JSON string containing all pull requests.
|
|
217
|
+
"""
|
|
218
|
+
try:
|
|
219
|
+
if state not in ["OPEN", "MERGED", "DECLINED", "SUPERSEDED"]:
|
|
220
|
+
logger.debug(f"Invalid pull request state: {state}. Defaulting to OPEN")
|
|
221
|
+
state = "OPEN"
|
|
222
|
+
|
|
223
|
+
params = {"state": state}
|
|
224
|
+
|
|
225
|
+
pull_requests = self._make_request(
|
|
226
|
+
"GET", f"/repositories/{self.workspace}/{self.repo_slug}/pullrequests", params=params
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
return json.dumps(pull_requests, indent=2)
|
|
230
|
+
except Exception as e:
|
|
231
|
+
logger.error(f"Error retrieving pull requests for {self.repo_slug}: {str(e)}")
|
|
232
|
+
return json.dumps({"error": str(e)})
|
|
233
|
+
|
|
234
|
+
def get_pull_request_details(self, pull_request_id: int) -> str:
|
|
235
|
+
"""
|
|
236
|
+
Retrieves a pull request for a repository.
|
|
237
|
+
Args:
|
|
238
|
+
pull_request_id (int): The ID of the pull request to retrieve.
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
str: A JSON string containing the pull request.
|
|
242
|
+
"""
|
|
243
|
+
try:
|
|
244
|
+
pull_request = self._make_request(
|
|
245
|
+
"GET", f"/repositories/{self.workspace}/{self.repo_slug}/pullrequests/{pull_request_id}"
|
|
246
|
+
)
|
|
247
|
+
return json.dumps(pull_request, indent=2)
|
|
248
|
+
except Exception as e:
|
|
249
|
+
logger.error(f"Error retrieving pull requests for {self.repo_slug}: {str(e)}")
|
|
250
|
+
return json.dumps({"error": str(e)})
|
|
251
|
+
|
|
252
|
+
def get_pull_request_changes(self, pull_request_id: int) -> str:
|
|
253
|
+
"""
|
|
254
|
+
Retrieves changes for a pull request in a repository.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
pull_request_id (int): The ID of the pull request to retrieve.
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
str: A markdown string containing the pull request diff.
|
|
261
|
+
"""
|
|
262
|
+
try:
|
|
263
|
+
diff = self._make_request(
|
|
264
|
+
"GET", f"/repositories/{self.workspace}/{self.repo_slug}/pullrequests/{pull_request_id}/diff"
|
|
265
|
+
)
|
|
266
|
+
if isinstance(diff, dict):
|
|
267
|
+
return json.dumps(diff, indent=2)
|
|
268
|
+
return diff
|
|
269
|
+
except Exception as e:
|
|
270
|
+
logger.error(f"Error retrieving changes for pull request {pull_request_id} in {self.repo_slug}: {str(e)}")
|
|
271
|
+
return json.dumps({"error": str(e)})
|
|
272
|
+
|
|
273
|
+
def list_issues(self, count: int = 10) -> str:
|
|
274
|
+
"""
|
|
275
|
+
Retrieves all issues for a repository.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
count (int, optional): The number of issues to retrieve. Defaults to 10. Maximum 50.
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
str: A JSON string containing all issues.
|
|
282
|
+
"""
|
|
283
|
+
try:
|
|
284
|
+
count = min(count, 50)
|
|
285
|
+
params = {"pagelen": count}
|
|
286
|
+
|
|
287
|
+
issues = self._make_request("GET", f"/repositories/{self.workspace}/{self.repo_slug}/issues", params=params)
|
|
288
|
+
|
|
289
|
+
return json.dumps(issues, indent=2)
|
|
290
|
+
except Exception as e:
|
|
291
|
+
logger.error(f"Error retrieving issues for {self.repo_slug}: {str(e)}")
|
|
292
|
+
return json.dumps({"error": str(e)})
|
agno/tools/brandfetch.py
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Going to contribute this to agno toolkits.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from os import getenv
|
|
6
|
+
from typing import Any, Optional
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
import httpx
|
|
10
|
+
except ImportError:
|
|
11
|
+
raise ImportError("`httpx` not installed.")
|
|
12
|
+
|
|
13
|
+
from agno.tools import Toolkit
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BrandfetchTools(Toolkit):
|
|
17
|
+
"""
|
|
18
|
+
Brandfetch API toolkit for retrieving brand data and searching brands.
|
|
19
|
+
|
|
20
|
+
Supports both Brand API (retrieve comprehensive brand data) and
|
|
21
|
+
Brand Search API (find and search brands by name).
|
|
22
|
+
|
|
23
|
+
-- Brand API
|
|
24
|
+
|
|
25
|
+
api_key: str - your Brandfetch API key
|
|
26
|
+
|
|
27
|
+
-- Brand Search API
|
|
28
|
+
|
|
29
|
+
client_id: str - your Brandfetch Client ID
|
|
30
|
+
|
|
31
|
+
all: bool - if True, will use all tools
|
|
32
|
+
enable_search_by_identifier: bool - if True, will use search by identifier
|
|
33
|
+
enable_search_by_brand: bool - if True, will use search by brand
|
|
34
|
+
enable_asearch_by_identifier: bool - if True, will use async search by identifier
|
|
35
|
+
enable_asearch_by_brand: bool - if True, will use async search by brand
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
api_key: Optional[str] = None,
|
|
41
|
+
client_id: Optional[str] = None,
|
|
42
|
+
base_url: str = "https://api.brandfetch.io/v2",
|
|
43
|
+
timeout: Optional[float] = 20.0,
|
|
44
|
+
enable_search_by_identifier: bool = True,
|
|
45
|
+
enable_search_by_brand: bool = False,
|
|
46
|
+
all: bool = False,
|
|
47
|
+
async_tools: bool = False,
|
|
48
|
+
**kwargs,
|
|
49
|
+
):
|
|
50
|
+
self.api_key = api_key or getenv("BRANDFETCH_API_KEY")
|
|
51
|
+
self.client_id = client_id or getenv("BRANDFETCH_CLIENT_ID")
|
|
52
|
+
self.base_url = base_url
|
|
53
|
+
self.timeout = httpx.Timeout(timeout)
|
|
54
|
+
self.search_url = f"{self.base_url}/search"
|
|
55
|
+
self.brand_url = f"{self.base_url}/brands"
|
|
56
|
+
|
|
57
|
+
tools: list[Any] = []
|
|
58
|
+
# Backward-compat mapping: prefer new enable_* flags, but honor legacy toggles
|
|
59
|
+
if async_tools:
|
|
60
|
+
if all or enable_search_by_identifier:
|
|
61
|
+
tools.append(self.asearch_by_identifier)
|
|
62
|
+
if all or enable_search_by_brand:
|
|
63
|
+
tools.append(self.asearch_by_brand)
|
|
64
|
+
else:
|
|
65
|
+
if all or enable_search_by_identifier:
|
|
66
|
+
tools.append(self.search_by_identifier)
|
|
67
|
+
if all or enable_search_by_brand:
|
|
68
|
+
tools.append(self.search_by_brand)
|
|
69
|
+
name = kwargs.pop("name", "brandfetch_tools")
|
|
70
|
+
super().__init__(name=name, tools=tools, **kwargs)
|
|
71
|
+
|
|
72
|
+
async def asearch_by_identifier(self, identifier: str) -> dict[str, Any]:
|
|
73
|
+
"""
|
|
74
|
+
Search for brand data by identifier (domain, brand id, isin, stock ticker).
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
identifier: Options are you can use: Domain (nike.com), Brand ID (id_0dwKPKT), ISIN (US6541061031), Stock Ticker (NKE)
|
|
78
|
+
Returns:
|
|
79
|
+
Dict containing brand data including logos, colors, fonts, and other brand assets
|
|
80
|
+
|
|
81
|
+
Raises:
|
|
82
|
+
ValueError: If no API key is provided
|
|
83
|
+
"""
|
|
84
|
+
if not self.api_key:
|
|
85
|
+
raise ValueError("API key is required for brand search by identifier")
|
|
86
|
+
|
|
87
|
+
url = f"{self.brand_url}/{identifier}"
|
|
88
|
+
headers = {"Authorization": f"Bearer {self.api_key}"}
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
92
|
+
response = await client.get(url, headers=headers)
|
|
93
|
+
response.raise_for_status()
|
|
94
|
+
return response.json()
|
|
95
|
+
except httpx.HTTPStatusError as e:
|
|
96
|
+
if e.response.status_code == 404:
|
|
97
|
+
return {"error": f"Brand not found for identifier: {identifier}"}
|
|
98
|
+
elif e.response.status_code == 401:
|
|
99
|
+
return {"error": "Invalid API key"}
|
|
100
|
+
elif e.response.status_code == 429:
|
|
101
|
+
return {"error": "Rate limit exceeded"}
|
|
102
|
+
else:
|
|
103
|
+
return {"error": f"API error: {e.response.status_code}"}
|
|
104
|
+
except httpx.RequestError as e:
|
|
105
|
+
return {"error": f"Request failed: {str(e)}"}
|
|
106
|
+
|
|
107
|
+
def search_by_identifier(self, identifier: str) -> dict[str, Any]:
|
|
108
|
+
"""
|
|
109
|
+
Search for brand data by identifier (domain, brand id, isin, stock ticker).
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
identifier: Options are you can use: Domain (nike.com), Brand ID (id_0dwKPKT), ISIN (US6541061031), Stock Ticker (NKE)
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
Dict containing brand data including logos, colors, fonts, and other brand assets
|
|
116
|
+
|
|
117
|
+
Raises:
|
|
118
|
+
ValueError: If no API key is provided
|
|
119
|
+
"""
|
|
120
|
+
if not self.api_key:
|
|
121
|
+
raise ValueError("API key is required for brand search by identifier")
|
|
122
|
+
|
|
123
|
+
url = f"{self.brand_url}/{identifier}"
|
|
124
|
+
headers = {"Authorization": f"Bearer {self.api_key}"}
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
with httpx.Client(timeout=self.timeout) as client:
|
|
128
|
+
response = client.get(url, headers=headers)
|
|
129
|
+
response.raise_for_status()
|
|
130
|
+
return response.json()
|
|
131
|
+
except httpx.HTTPStatusError as e:
|
|
132
|
+
if e.response.status_code == 404:
|
|
133
|
+
return {"error": f"Brand not found for identifier: {identifier}"}
|
|
134
|
+
elif e.response.status_code == 401:
|
|
135
|
+
return {"error": "Invalid API key"}
|
|
136
|
+
elif e.response.status_code == 429:
|
|
137
|
+
return {"error": "Rate limit exceeded"}
|
|
138
|
+
else:
|
|
139
|
+
return {"error": f"API error: {e.response.status_code}"}
|
|
140
|
+
except httpx.RequestError as e:
|
|
141
|
+
return {"error": f"Request failed: {str(e)}"}
|
|
142
|
+
|
|
143
|
+
async def asearch_by_brand(self, name: str) -> dict[str, Any]:
|
|
144
|
+
"""
|
|
145
|
+
Search for brands by name using the Brand Search API - can give you the right brand id to use for the brand api.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
name: Brand name to search for (e.g., 'Google', 'Apple')
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Dict containing search results with brand matches
|
|
152
|
+
|
|
153
|
+
Raises:
|
|
154
|
+
ValueError: If no client ID is provided
|
|
155
|
+
"""
|
|
156
|
+
if not self.client_id:
|
|
157
|
+
raise ValueError("Client ID is required for brand search by name")
|
|
158
|
+
|
|
159
|
+
url = f"{self.search_url}/{name}"
|
|
160
|
+
params = {"c": self.client_id}
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
164
|
+
response = await client.get(url, params=params)
|
|
165
|
+
response.raise_for_status()
|
|
166
|
+
return response.json()
|
|
167
|
+
except httpx.HTTPStatusError as e:
|
|
168
|
+
if e.response.status_code == 404:
|
|
169
|
+
return {"error": f"No brands found for name: {name}"}
|
|
170
|
+
elif e.response.status_code == 401:
|
|
171
|
+
return {"error": "Invalid client ID"}
|
|
172
|
+
elif e.response.status_code == 429:
|
|
173
|
+
return {"error": "Rate limit exceeded"}
|
|
174
|
+
else:
|
|
175
|
+
return {"error": f"API error: {e.response.status_code}"}
|
|
176
|
+
except httpx.RequestError as e:
|
|
177
|
+
return {"error": f"Request failed: {str(e)}"}
|
|
178
|
+
|
|
179
|
+
def search_by_brand(self, name: str) -> dict[str, Any]:
|
|
180
|
+
"""
|
|
181
|
+
Search for brands by name using the Brand Search API - can give you the right brand id to use for the brand api.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
name: Brand name to search for (e.g., 'Google', 'Apple')
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Dict containing search results with brand matches
|
|
188
|
+
|
|
189
|
+
Raises:
|
|
190
|
+
ValueError: If no client ID is provided
|
|
191
|
+
"""
|
|
192
|
+
if not self.client_id:
|
|
193
|
+
raise ValueError("Client ID is required for brand search by name")
|
|
194
|
+
|
|
195
|
+
url = f"{self.search_url}/{name}"
|
|
196
|
+
params = {"c": self.client_id}
|
|
197
|
+
|
|
198
|
+
try:
|
|
199
|
+
with httpx.Client(timeout=self.timeout) as client:
|
|
200
|
+
response = client.get(url, params=params)
|
|
201
|
+
response.raise_for_status()
|
|
202
|
+
return response.json()
|
|
203
|
+
except httpx.HTTPStatusError as e:
|
|
204
|
+
if e.response.status_code == 404:
|
|
205
|
+
return {"error": f"No brands found for name: {name}"}
|
|
206
|
+
elif e.response.status_code == 401:
|
|
207
|
+
return {"error": "Invalid client ID"}
|
|
208
|
+
elif e.response.status_code == 429:
|
|
209
|
+
return {"error": "Rate limit exceeded"}
|
|
210
|
+
else:
|
|
211
|
+
return {"error": f"API error: {e.response.status_code}"}
|
|
212
|
+
except httpx.RequestError as e:
|
|
213
|
+
return {"error": f"Request failed: {str(e)}"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from os import getenv
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from agno.tools import Toolkit
|
|
6
|
+
from agno.utils.log import log_info
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from brave import Brave
|
|
10
|
+
except ImportError:
|
|
11
|
+
raise ImportError("`brave-search` not installed. Please install using `pip install brave-search`")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BraveSearchTools(Toolkit):
|
|
15
|
+
"""
|
|
16
|
+
BraveSearch is a toolkit for searching Brave easily.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
api_key (str, optional): Brave API key. If not provided, will use BRAVE_API_KEY environment variable.
|
|
20
|
+
fixed_max_results (Optional[int]): A fixed number of maximum results.
|
|
21
|
+
fixed_language (Optional[str]): A fixed language for the search results.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
api_key: Optional[str] = None,
|
|
27
|
+
fixed_max_results: Optional[int] = None,
|
|
28
|
+
fixed_language: Optional[str] = None,
|
|
29
|
+
enable_brave_search: bool = True,
|
|
30
|
+
all: bool = False,
|
|
31
|
+
**kwargs,
|
|
32
|
+
):
|
|
33
|
+
self.api_key = api_key or getenv("BRAVE_API_KEY")
|
|
34
|
+
if not self.api_key:
|
|
35
|
+
raise ValueError("BRAVE_API_KEY is required. Please set the BRAVE_API_KEY environment variable.")
|
|
36
|
+
|
|
37
|
+
self.fixed_max_results = fixed_max_results
|
|
38
|
+
self.fixed_language = fixed_language
|
|
39
|
+
|
|
40
|
+
self.brave_client = Brave(api_key=self.api_key)
|
|
41
|
+
|
|
42
|
+
tools = []
|
|
43
|
+
if all or enable_brave_search:
|
|
44
|
+
tools.append(self.brave_search)
|
|
45
|
+
|
|
46
|
+
super().__init__(
|
|
47
|
+
name="brave_search",
|
|
48
|
+
tools=tools,
|
|
49
|
+
**kwargs,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
def brave_search(
|
|
53
|
+
self,
|
|
54
|
+
query: str,
|
|
55
|
+
max_results: int = 5,
|
|
56
|
+
country: str = "US",
|
|
57
|
+
search_lang: str = "en",
|
|
58
|
+
) -> str:
|
|
59
|
+
"""
|
|
60
|
+
Search Brave for the specified query and return the results.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
query (str): The query to search for.
|
|
64
|
+
max_results (int, optional): The maximum number of results to return. Default is 5.
|
|
65
|
+
country (str, optional): The country code for search results. Default is "US".
|
|
66
|
+
search_lang (str, optional): The language of the search results. Default is "en".
|
|
67
|
+
Returns:
|
|
68
|
+
str: A JSON formatted string containing the search results.
|
|
69
|
+
"""
|
|
70
|
+
final_max_results = self.fixed_max_results if self.fixed_max_results is not None else max_results
|
|
71
|
+
final_search_lang = self.fixed_language if self.fixed_language is not None else search_lang
|
|
72
|
+
|
|
73
|
+
if not query:
|
|
74
|
+
return json.dumps({"error": "Please provide a query to search for"})
|
|
75
|
+
|
|
76
|
+
log_info(f"Searching Brave for: {query}")
|
|
77
|
+
|
|
78
|
+
search_params = {
|
|
79
|
+
"q": query,
|
|
80
|
+
"count": final_max_results,
|
|
81
|
+
"country": country,
|
|
82
|
+
"search_lang": final_search_lang,
|
|
83
|
+
"result_filter": "web",
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
search_results = self.brave_client.search(**search_params)
|
|
87
|
+
|
|
88
|
+
filtered_results = {
|
|
89
|
+
"web_results": [],
|
|
90
|
+
"query": query,
|
|
91
|
+
"total_results": 0,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if hasattr(search_results, "web") and search_results.web:
|
|
95
|
+
web_results = []
|
|
96
|
+
for result in search_results.web.results:
|
|
97
|
+
web_result = {
|
|
98
|
+
"title": result.title,
|
|
99
|
+
"url": str(result.url),
|
|
100
|
+
"description": result.description,
|
|
101
|
+
}
|
|
102
|
+
web_results.append(web_result)
|
|
103
|
+
filtered_results["web_results"] = web_results
|
|
104
|
+
filtered_results["total_results"] = len(web_results)
|
|
105
|
+
|
|
106
|
+
return json.dumps(filtered_results, indent=2)
|