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
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
from collections.abc import AsyncIterator
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from os import getenv
|
|
4
|
+
from typing import Any, Dict, Iterator, List, Optional, Type, Union
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
|
|
9
|
+
from agno.exceptions import ModelProviderError
|
|
10
|
+
from agno.models.base import Model
|
|
11
|
+
from agno.models.message import Message
|
|
12
|
+
from agno.models.metrics import Metrics
|
|
13
|
+
from agno.models.response import ModelResponse
|
|
14
|
+
from agno.run.agent import RunOutput
|
|
15
|
+
from agno.utils.log import log_debug, log_error
|
|
16
|
+
from agno.utils.models.ai_foundry import format_message
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
from azure.ai.inference import ChatCompletionsClient
|
|
20
|
+
from azure.ai.inference.aio import ChatCompletionsClient as AsyncChatCompletionsClient
|
|
21
|
+
from azure.ai.inference.models import (
|
|
22
|
+
ChatCompletions,
|
|
23
|
+
ChatCompletionsToolDefinition,
|
|
24
|
+
FunctionDefinition,
|
|
25
|
+
JsonSchemaFormat,
|
|
26
|
+
StreamingChatCompletionsUpdate,
|
|
27
|
+
StreamingChatResponseToolCallUpdate,
|
|
28
|
+
)
|
|
29
|
+
from azure.core.credentials import AzureKeyCredential
|
|
30
|
+
from azure.core.exceptions import HttpResponseError
|
|
31
|
+
except ImportError:
|
|
32
|
+
raise ImportError(
|
|
33
|
+
"`azure-ai-inference` not installed. Please install it via `pip install azure-ai-inference aiohttp`."
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class AzureAIFoundry(Model):
|
|
39
|
+
"""
|
|
40
|
+
A class for interacting with Azure AI Interface models.
|
|
41
|
+
|
|
42
|
+
- For Managed Compute, set the `api_key` to your Azure AI Foundry API key and the `azure_endpoint` to the endpoint URL in the format `https://<your-host-name>.<your-azure-region>.models.ai.azure.com/models`
|
|
43
|
+
- For Serverless API, set the `api_key` to your Azure AI Foundry API key and the `azure_endpoint` to the endpoint URL in the format `https://<your-host-name>.<your-azure-region>.models.ai.azure.com/models`
|
|
44
|
+
- For Github Models, set the `api_key` to the Github Personal Access Token.
|
|
45
|
+
- For Azure OpenAI, set the `api_key` to your Azure AI Foundry API key, the `api_version` to `2024-06-01` and the `azure_endpoint` to the endpoint URL in the format `https://<your-resource-name>.openai.azure.com/openai/deployments/<your-deployment-name>`
|
|
46
|
+
|
|
47
|
+
For more information, see: https://learn.microsoft.com/en-gb/python/api/overview/azure/ai-inference-readme
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
id: str = "gpt-4o"
|
|
51
|
+
name: str = "AzureAIFoundry"
|
|
52
|
+
provider: str = "Azure"
|
|
53
|
+
|
|
54
|
+
# Request parameters
|
|
55
|
+
temperature: Optional[float] = None
|
|
56
|
+
max_tokens: Optional[int] = None
|
|
57
|
+
frequency_penalty: Optional[float] = None
|
|
58
|
+
presence_penalty: Optional[float] = None
|
|
59
|
+
top_p: Optional[float] = None
|
|
60
|
+
stop: Optional[Union[str, List[str]]] = None
|
|
61
|
+
seed: Optional[int] = None
|
|
62
|
+
model_extras: Optional[Dict[str, Any]] = None
|
|
63
|
+
strict_output: bool = True # When True, guarantees schema adherence for structured outputs. When False, attempts to follow schema as a guide but may occasionally deviate
|
|
64
|
+
request_params: Optional[Dict[str, Any]] = None
|
|
65
|
+
# Client parameters
|
|
66
|
+
api_key: Optional[str] = None
|
|
67
|
+
api_version: Optional[str] = None
|
|
68
|
+
azure_endpoint: Optional[str] = None
|
|
69
|
+
timeout: Optional[float] = None
|
|
70
|
+
max_retries: Optional[int] = None
|
|
71
|
+
http_client: Optional[httpx.Client] = None
|
|
72
|
+
client_params: Optional[Dict[str, Any]] = None
|
|
73
|
+
|
|
74
|
+
# Azure AI clients
|
|
75
|
+
client: Optional[ChatCompletionsClient] = None
|
|
76
|
+
async_client: Optional[AsyncChatCompletionsClient] = None
|
|
77
|
+
|
|
78
|
+
def get_request_params(
|
|
79
|
+
self,
|
|
80
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
81
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
82
|
+
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
83
|
+
) -> Dict[str, Any]:
|
|
84
|
+
"""Get the parameters for creating an Azure AI request."""
|
|
85
|
+
base_params = {
|
|
86
|
+
"temperature": self.temperature,
|
|
87
|
+
"max_tokens": self.max_tokens,
|
|
88
|
+
"frequency_penalty": self.frequency_penalty,
|
|
89
|
+
"presence_penalty": self.presence_penalty,
|
|
90
|
+
"top_p": self.top_p,
|
|
91
|
+
"stop": self.stop,
|
|
92
|
+
"seed": self.seed,
|
|
93
|
+
"model": self.id,
|
|
94
|
+
"model_extras": self.model_extras,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if tools:
|
|
98
|
+
parsed_tools = []
|
|
99
|
+
for _tool in tools:
|
|
100
|
+
parsed_tools.append(
|
|
101
|
+
ChatCompletionsToolDefinition(
|
|
102
|
+
function=FunctionDefinition(
|
|
103
|
+
name=_tool["function"]["name"],
|
|
104
|
+
description=_tool["function"]["description"],
|
|
105
|
+
parameters=_tool["function"]["parameters"],
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
)
|
|
109
|
+
base_params["tools"] = parsed_tools # type: ignore
|
|
110
|
+
if tool_choice:
|
|
111
|
+
base_params["tool_choice"] = tool_choice
|
|
112
|
+
|
|
113
|
+
if response_format is not None:
|
|
114
|
+
if isinstance(response_format, type) and issubclass(response_format, BaseModel):
|
|
115
|
+
base_params["response_format"] = ( # type: ignore
|
|
116
|
+
JsonSchemaFormat(
|
|
117
|
+
name=response_format.__name__,
|
|
118
|
+
schema=response_format.model_json_schema(), # type: ignore
|
|
119
|
+
description=response_format.__doc__,
|
|
120
|
+
strict=self.strict_output,
|
|
121
|
+
),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
request_params = {k: v for k, v in base_params.items() if v is not None}
|
|
125
|
+
if self.request_params:
|
|
126
|
+
request_params.update(self.request_params)
|
|
127
|
+
|
|
128
|
+
if request_params:
|
|
129
|
+
log_debug(f"Calling {self.provider} with request parameters: {request_params}", log_level=2)
|
|
130
|
+
return request_params
|
|
131
|
+
|
|
132
|
+
def _get_client_params(self) -> Dict[str, Any]:
|
|
133
|
+
"""Get the parameters for creating an Azure AI client."""
|
|
134
|
+
self.api_key = self.api_key or getenv("AZURE_API_KEY")
|
|
135
|
+
self.api_version = self.api_version or getenv("AZURE_API_VERSION", "2024-05-01-preview")
|
|
136
|
+
self.azure_endpoint = self.azure_endpoint or getenv("AZURE_ENDPOINT")
|
|
137
|
+
|
|
138
|
+
if not self.api_key:
|
|
139
|
+
log_error("AZURE_API_KEY not set. Please set the AZURE_API_KEY environment variable.")
|
|
140
|
+
if not self.azure_endpoint:
|
|
141
|
+
log_error("AZURE_ENDPOINT not set. Please set the AZURE_ENDPOINT environment variable.")
|
|
142
|
+
|
|
143
|
+
base_params = {
|
|
144
|
+
"endpoint": self.azure_endpoint,
|
|
145
|
+
"credential": AzureKeyCredential(self.api_key),
|
|
146
|
+
"api_version": self.api_version,
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
# Create client_params dict with non-None values
|
|
150
|
+
client_params = {k: v for k, v in base_params.items() if v is not None}
|
|
151
|
+
# Add additional client params if provided
|
|
152
|
+
if self.client_params:
|
|
153
|
+
client_params.update(self.client_params)
|
|
154
|
+
|
|
155
|
+
return client_params
|
|
156
|
+
|
|
157
|
+
def get_client(self) -> ChatCompletionsClient:
|
|
158
|
+
"""
|
|
159
|
+
Returns an Azure AI client.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
ChatCompletionsClient: An instance of the Azure AI client.
|
|
163
|
+
"""
|
|
164
|
+
# Check if client exists and is not closed
|
|
165
|
+
# Azure's client doesn't have is_closed(), so we check if _client exists
|
|
166
|
+
if self.client and hasattr(self.client, "_client"):
|
|
167
|
+
return self.client
|
|
168
|
+
|
|
169
|
+
client_params = self._get_client_params()
|
|
170
|
+
self.client = ChatCompletionsClient(**client_params)
|
|
171
|
+
return self.client
|
|
172
|
+
|
|
173
|
+
def get_async_client(self) -> AsyncChatCompletionsClient:
|
|
174
|
+
"""
|
|
175
|
+
Returns an asynchronous Azure AI client.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
AsyncChatCompletionsClient: An instance of the asynchronous Azure AI client.
|
|
179
|
+
"""
|
|
180
|
+
# Check if client exists and is not closed
|
|
181
|
+
# Azure's async client doesn't have is_closed(), so we check if _client exists
|
|
182
|
+
if self.async_client and hasattr(self.async_client, "_client"):
|
|
183
|
+
return self.async_client
|
|
184
|
+
|
|
185
|
+
client_params = self._get_client_params()
|
|
186
|
+
|
|
187
|
+
self.async_client = AsyncChatCompletionsClient(**client_params)
|
|
188
|
+
return self.async_client
|
|
189
|
+
|
|
190
|
+
def close(self) -> None:
|
|
191
|
+
"""Close the synchronous client and clean up resources."""
|
|
192
|
+
if self.client:
|
|
193
|
+
self.client.close()
|
|
194
|
+
self.client = None
|
|
195
|
+
|
|
196
|
+
async def aclose(self) -> None:
|
|
197
|
+
"""Close the asynchronous client and clean up resources."""
|
|
198
|
+
if self.async_client:
|
|
199
|
+
await self.async_client.close()
|
|
200
|
+
self.async_client = None
|
|
201
|
+
|
|
202
|
+
def invoke(
|
|
203
|
+
self,
|
|
204
|
+
messages: List[Message],
|
|
205
|
+
assistant_message: Message,
|
|
206
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
207
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
208
|
+
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
209
|
+
run_response: Optional[RunOutput] = None,
|
|
210
|
+
compress_tool_results: bool = False,
|
|
211
|
+
) -> ModelResponse:
|
|
212
|
+
"""
|
|
213
|
+
Send a chat completion request to the Azure AI API.
|
|
214
|
+
"""
|
|
215
|
+
try:
|
|
216
|
+
if run_response and run_response.metrics:
|
|
217
|
+
run_response.metrics.set_time_to_first_token()
|
|
218
|
+
|
|
219
|
+
assistant_message.metrics.start_timer()
|
|
220
|
+
provider_response = self.get_client().complete(
|
|
221
|
+
messages=[format_message(m, compress_tool_results) for m in messages],
|
|
222
|
+
**self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
|
|
223
|
+
)
|
|
224
|
+
assistant_message.metrics.stop_timer()
|
|
225
|
+
|
|
226
|
+
model_response = self._parse_provider_response(provider_response, response_format=response_format)
|
|
227
|
+
|
|
228
|
+
return model_response
|
|
229
|
+
|
|
230
|
+
except HttpResponseError as e:
|
|
231
|
+
log_error(f"Azure AI API error: {e}")
|
|
232
|
+
raise ModelProviderError(
|
|
233
|
+
message=e.reason or "Azure AI API error",
|
|
234
|
+
status_code=e.status_code or 502,
|
|
235
|
+
model_name=self.name,
|
|
236
|
+
model_id=self.id,
|
|
237
|
+
) from e
|
|
238
|
+
except Exception as e:
|
|
239
|
+
log_error(f"Error from Azure AI API: {e}")
|
|
240
|
+
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
241
|
+
|
|
242
|
+
async def ainvoke(
|
|
243
|
+
self,
|
|
244
|
+
messages: List[Message],
|
|
245
|
+
assistant_message: Message,
|
|
246
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
247
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
248
|
+
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
249
|
+
run_response: Optional[RunOutput] = None,
|
|
250
|
+
compress_tool_results: bool = False,
|
|
251
|
+
) -> ModelResponse:
|
|
252
|
+
"""
|
|
253
|
+
Sends an asynchronous chat completion request to the Azure AI API.
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
try:
|
|
257
|
+
if run_response and run_response.metrics:
|
|
258
|
+
run_response.metrics.set_time_to_first_token()
|
|
259
|
+
|
|
260
|
+
assistant_message.metrics.start_timer()
|
|
261
|
+
provider_response = await self.get_async_client().complete(
|
|
262
|
+
messages=[format_message(m, compress_tool_results) for m in messages],
|
|
263
|
+
**self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
|
|
264
|
+
)
|
|
265
|
+
assistant_message.metrics.stop_timer()
|
|
266
|
+
|
|
267
|
+
model_response = self._parse_provider_response(provider_response, response_format=response_format) # type: ignore
|
|
268
|
+
|
|
269
|
+
return model_response
|
|
270
|
+
|
|
271
|
+
except HttpResponseError as e:
|
|
272
|
+
log_error(f"Azure AI API error: {e}")
|
|
273
|
+
raise ModelProviderError(
|
|
274
|
+
message=e.reason or "Azure AI API error",
|
|
275
|
+
status_code=e.status_code or 502,
|
|
276
|
+
model_name=self.name,
|
|
277
|
+
model_id=self.id,
|
|
278
|
+
) from e
|
|
279
|
+
except Exception as e:
|
|
280
|
+
log_error(f"Error from Azure AI API: {e}")
|
|
281
|
+
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
282
|
+
|
|
283
|
+
def invoke_stream(
|
|
284
|
+
self,
|
|
285
|
+
messages: List[Message],
|
|
286
|
+
assistant_message: Message,
|
|
287
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
288
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
289
|
+
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
290
|
+
run_response: Optional[RunOutput] = None,
|
|
291
|
+
compress_tool_results: bool = False,
|
|
292
|
+
) -> Iterator[ModelResponse]:
|
|
293
|
+
"""
|
|
294
|
+
Send a streaming chat completion request to the Azure AI API.
|
|
295
|
+
"""
|
|
296
|
+
try:
|
|
297
|
+
if run_response and run_response.metrics:
|
|
298
|
+
run_response.metrics.set_time_to_first_token()
|
|
299
|
+
|
|
300
|
+
assistant_message.metrics.start_timer()
|
|
301
|
+
|
|
302
|
+
for chunk in self.get_client().complete(
|
|
303
|
+
messages=[format_message(m, compress_tool_results) for m in messages],
|
|
304
|
+
stream=True,
|
|
305
|
+
**self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
|
|
306
|
+
):
|
|
307
|
+
yield self._parse_provider_response_delta(chunk)
|
|
308
|
+
|
|
309
|
+
assistant_message.metrics.stop_timer()
|
|
310
|
+
|
|
311
|
+
except HttpResponseError as e:
|
|
312
|
+
log_error(f"Azure AI API error: {e}")
|
|
313
|
+
raise ModelProviderError(
|
|
314
|
+
message=e.reason or "Azure AI API error",
|
|
315
|
+
status_code=e.status_code or 502,
|
|
316
|
+
model_name=self.name,
|
|
317
|
+
model_id=self.id,
|
|
318
|
+
) from e
|
|
319
|
+
except Exception as e:
|
|
320
|
+
log_error(f"Error from Azure AI API: {e}")
|
|
321
|
+
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
322
|
+
|
|
323
|
+
async def ainvoke_stream(
|
|
324
|
+
self,
|
|
325
|
+
messages: List[Message],
|
|
326
|
+
assistant_message: Message,
|
|
327
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
328
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
329
|
+
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
330
|
+
run_response: Optional[RunOutput] = None,
|
|
331
|
+
compress_tool_results: bool = False,
|
|
332
|
+
) -> AsyncIterator[ModelResponse]:
|
|
333
|
+
"""
|
|
334
|
+
Sends an asynchronous streaming chat completion request to the Azure AI API.
|
|
335
|
+
"""
|
|
336
|
+
try:
|
|
337
|
+
if run_response and run_response.metrics:
|
|
338
|
+
run_response.metrics.set_time_to_first_token()
|
|
339
|
+
|
|
340
|
+
assistant_message.metrics.start_timer()
|
|
341
|
+
|
|
342
|
+
async_stream = await self.get_async_client().complete(
|
|
343
|
+
messages=[format_message(m, compress_tool_results) for m in messages],
|
|
344
|
+
stream=True,
|
|
345
|
+
**self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
|
|
346
|
+
)
|
|
347
|
+
async for chunk in async_stream: # type: ignore
|
|
348
|
+
yield self._parse_provider_response_delta(chunk)
|
|
349
|
+
|
|
350
|
+
assistant_message.metrics.stop_timer()
|
|
351
|
+
|
|
352
|
+
except HttpResponseError as e:
|
|
353
|
+
log_error(f"Azure AI API error: {e}")
|
|
354
|
+
raise ModelProviderError(
|
|
355
|
+
message=e.reason or "Azure AI API error",
|
|
356
|
+
status_code=e.status_code or 502,
|
|
357
|
+
model_name=self.name,
|
|
358
|
+
model_id=self.id,
|
|
359
|
+
) from e
|
|
360
|
+
except Exception as e:
|
|
361
|
+
log_error(f"Error from Azure AI API: {e}")
|
|
362
|
+
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
363
|
+
|
|
364
|
+
def _parse_provider_response(self, response: ChatCompletions, **kwargs) -> ModelResponse:
|
|
365
|
+
"""
|
|
366
|
+
Parse the Azure AI response into a ModelResponse.
|
|
367
|
+
|
|
368
|
+
Args:
|
|
369
|
+
response: Raw response from Azure AI
|
|
370
|
+
|
|
371
|
+
Returns:
|
|
372
|
+
ModelResponse: Parsed response data
|
|
373
|
+
"""
|
|
374
|
+
model_response = ModelResponse()
|
|
375
|
+
|
|
376
|
+
try:
|
|
377
|
+
# Get the first choice from the response
|
|
378
|
+
choice = response.choices[0]
|
|
379
|
+
|
|
380
|
+
# Add content
|
|
381
|
+
if choice.message.content is not None:
|
|
382
|
+
model_response.content = choice.message.content
|
|
383
|
+
|
|
384
|
+
# Add role
|
|
385
|
+
if choice.message.role is not None:
|
|
386
|
+
model_response.role = choice.message.role
|
|
387
|
+
|
|
388
|
+
# Add tool calls if present
|
|
389
|
+
if choice.message.tool_calls and len(choice.message.tool_calls) > 0:
|
|
390
|
+
model_response.tool_calls = [
|
|
391
|
+
{
|
|
392
|
+
"id": t.id,
|
|
393
|
+
"type": t.type,
|
|
394
|
+
"function": {
|
|
395
|
+
"name": t.function.name,
|
|
396
|
+
"arguments": t.function.arguments,
|
|
397
|
+
},
|
|
398
|
+
}
|
|
399
|
+
for t in choice.message.tool_calls
|
|
400
|
+
]
|
|
401
|
+
|
|
402
|
+
# Add usage metrics if present
|
|
403
|
+
if response.usage is not None:
|
|
404
|
+
model_response.response_usage = self._get_metrics(response.usage)
|
|
405
|
+
|
|
406
|
+
except Exception as e:
|
|
407
|
+
log_error(f"Error parsing Azure AI response: {e}")
|
|
408
|
+
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
409
|
+
|
|
410
|
+
return model_response
|
|
411
|
+
|
|
412
|
+
# Override base method
|
|
413
|
+
@staticmethod
|
|
414
|
+
def parse_tool_calls(tool_calls_data: List[StreamingChatResponseToolCallUpdate]) -> List[Dict[str, Any]]:
|
|
415
|
+
"""
|
|
416
|
+
Build tool calls from streamed tool call data.
|
|
417
|
+
|
|
418
|
+
Args:
|
|
419
|
+
tool_calls_data (List[StreamingChatResponseToolCallUpdate]): The tool call data to build from.
|
|
420
|
+
|
|
421
|
+
Returns:
|
|
422
|
+
List[Dict[str, Any]]: The built tool calls.
|
|
423
|
+
"""
|
|
424
|
+
tool_calls: List[Dict[str, Any]] = []
|
|
425
|
+
|
|
426
|
+
current_tool_call: Dict[str, Any] = {}
|
|
427
|
+
for tool_call in tool_calls_data:
|
|
428
|
+
if tool_call.id: # New tool call starts
|
|
429
|
+
if current_tool_call: # Store previous tool call if exists
|
|
430
|
+
tool_calls.append(current_tool_call)
|
|
431
|
+
current_tool_call = {
|
|
432
|
+
"id": tool_call.id,
|
|
433
|
+
"type": "function",
|
|
434
|
+
"function": {"name": tool_call.function.name, "arguments": tool_call.function.arguments or ""},
|
|
435
|
+
}
|
|
436
|
+
elif current_tool_call and tool_call.function and tool_call.function.arguments:
|
|
437
|
+
# Append arguments to current tool call
|
|
438
|
+
current_tool_call["function"]["arguments"] += tool_call.function.arguments
|
|
439
|
+
|
|
440
|
+
if current_tool_call: # Append final tool call
|
|
441
|
+
tool_calls.append(current_tool_call)
|
|
442
|
+
|
|
443
|
+
return tool_calls
|
|
444
|
+
|
|
445
|
+
def _parse_provider_response_delta(self, response_delta: StreamingChatCompletionsUpdate) -> ModelResponse:
|
|
446
|
+
"""
|
|
447
|
+
Parse the Azure AI streaming response into ModelResponse objects.
|
|
448
|
+
|
|
449
|
+
Args:
|
|
450
|
+
response_delta: Raw response chunk from Azure AI
|
|
451
|
+
|
|
452
|
+
Returns:
|
|
453
|
+
ModelResponse: Parsed response data
|
|
454
|
+
"""
|
|
455
|
+
model_response = ModelResponse()
|
|
456
|
+
|
|
457
|
+
try:
|
|
458
|
+
if response_delta.choices and len(response_delta.choices) > 0:
|
|
459
|
+
choice_delta = response_delta.choices[0].delta
|
|
460
|
+
|
|
461
|
+
if choice_delta:
|
|
462
|
+
# Add content
|
|
463
|
+
if choice_delta.content is not None:
|
|
464
|
+
model_response.content = choice_delta.content
|
|
465
|
+
|
|
466
|
+
# Add tool calls if present
|
|
467
|
+
if choice_delta.tool_calls and len(choice_delta.tool_calls) > 0:
|
|
468
|
+
model_response.tool_calls = choice_delta.tool_calls # type: ignore
|
|
469
|
+
# Add usage metrics if present
|
|
470
|
+
if response_delta.usage is not None:
|
|
471
|
+
model_response.response_usage = self._get_metrics(response_delta.usage)
|
|
472
|
+
|
|
473
|
+
except Exception as e:
|
|
474
|
+
log_error(f"Error parsing Azure AI response delta: {e}")
|
|
475
|
+
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
476
|
+
|
|
477
|
+
return model_response
|
|
478
|
+
|
|
479
|
+
def _get_metrics(self, response_usage) -> Metrics:
|
|
480
|
+
"""
|
|
481
|
+
Parse the given Azure AI Foundry usage into an Agno Metrics object.
|
|
482
|
+
"""
|
|
483
|
+
metrics = Metrics()
|
|
484
|
+
|
|
485
|
+
metrics.input_tokens = response_usage.get("prompt_tokens", 0)
|
|
486
|
+
metrics.output_tokens = response_usage.get("completion_tokens", 0)
|
|
487
|
+
metrics.total_tokens = metrics.input_tokens + metrics.output_tokens
|
|
488
|
+
|
|
489
|
+
return metrics
|
agno/models/azure/openai_chat.py
CHANGED
|
@@ -4,13 +4,16 @@ from typing import Any, Dict, Optional
|
|
|
4
4
|
|
|
5
5
|
import httpx
|
|
6
6
|
|
|
7
|
+
from agno.exceptions import ModelAuthenticationError
|
|
7
8
|
from agno.models.openai.like import OpenAILike
|
|
9
|
+
from agno.utils.http import get_default_async_client, get_default_sync_client
|
|
10
|
+
from agno.utils.log import log_warning
|
|
8
11
|
|
|
9
12
|
try:
|
|
10
13
|
from openai import AsyncAzureOpenAI as AsyncAzureOpenAIClient
|
|
11
14
|
from openai import AzureOpenAI as AzureOpenAIClient
|
|
12
|
-
except
|
|
13
|
-
raise ImportError("`
|
|
15
|
+
except ImportError:
|
|
16
|
+
raise ImportError("`openai` not installed. Please install using `pip install openai`")
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
@dataclass
|
|
@@ -31,20 +34,68 @@ class AzureOpenAI(OpenAILike):
|
|
|
31
34
|
azure_ad_token (Optional[str]): The Azure AD token to use.
|
|
32
35
|
azure_ad_token_provider (Optional[Any]): The Azure AD token provider to use.
|
|
33
36
|
organization (Optional[str]): The organization to use.
|
|
34
|
-
|
|
37
|
+
client (Optional[AzureOpenAIClient]): The OpenAI client to use.
|
|
38
|
+
async_client (Optional[AsyncAzureOpenAIClient]): The OpenAI client to use.
|
|
35
39
|
"""
|
|
36
40
|
|
|
37
41
|
id: str
|
|
38
42
|
name: str = "AzureOpenAI"
|
|
39
43
|
provider: str = "Azure"
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
supports_native_structured_outputs: bool = True
|
|
46
|
+
|
|
47
|
+
api_key: Optional[str] = None
|
|
48
|
+
api_version: Optional[str] = "2024-10-21"
|
|
49
|
+
azure_endpoint: Optional[str] = None
|
|
50
|
+
azure_deployment: Optional[str] = None
|
|
51
|
+
base_url: Optional[str] = None
|
|
45
52
|
azure_ad_token: Optional[str] = None
|
|
46
53
|
azure_ad_token_provider: Optional[Any] = None
|
|
47
|
-
|
|
54
|
+
|
|
55
|
+
default_headers: Optional[Dict[str, str]] = None
|
|
56
|
+
default_query: Optional[Dict[str, Any]] = None
|
|
57
|
+
|
|
58
|
+
client: Optional[AzureOpenAIClient] = None
|
|
59
|
+
async_client: Optional[AsyncAzureOpenAIClient] = None
|
|
60
|
+
|
|
61
|
+
def _get_client_params(self) -> Dict[str, Any]:
|
|
62
|
+
_client_params: Dict[str, Any] = {}
|
|
63
|
+
|
|
64
|
+
self.api_key = self.api_key or getenv("AZURE_OPENAI_API_KEY")
|
|
65
|
+
self.azure_endpoint = self.azure_endpoint or getenv("AZURE_OPENAI_ENDPOINT")
|
|
66
|
+
self.azure_deployment = self.azure_deployment or getenv("AZURE_OPENAI_DEPLOYMENT")
|
|
67
|
+
|
|
68
|
+
if not (self.api_key or self.azure_ad_token):
|
|
69
|
+
if not self.api_key:
|
|
70
|
+
raise ModelAuthenticationError(
|
|
71
|
+
message="AZURE_OPENAI_API_KEY not set. Please set the AZURE_OPENAI_API_KEY environment variable.",
|
|
72
|
+
model_name=self.name,
|
|
73
|
+
)
|
|
74
|
+
if not self.azure_ad_token:
|
|
75
|
+
raise ModelAuthenticationError(
|
|
76
|
+
message="AZURE_AD_TOKEN not set. Please set the AZURE_AD_TOKEN environment variable.",
|
|
77
|
+
model_name=self.name,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
params_mapping = {
|
|
81
|
+
"api_key": self.api_key,
|
|
82
|
+
"api_version": self.api_version,
|
|
83
|
+
"organization": self.organization,
|
|
84
|
+
"azure_endpoint": self.azure_endpoint,
|
|
85
|
+
"azure_deployment": self.azure_deployment,
|
|
86
|
+
"base_url": self.base_url,
|
|
87
|
+
"azure_ad_token": self.azure_ad_token,
|
|
88
|
+
"azure_ad_token_provider": self.azure_ad_token_provider,
|
|
89
|
+
}
|
|
90
|
+
if self.default_headers is not None:
|
|
91
|
+
_client_params["default_headers"] = self.default_headers
|
|
92
|
+
if self.default_query is not None:
|
|
93
|
+
_client_params["default_query"] = self.default_query
|
|
94
|
+
|
|
95
|
+
_client_params.update({k: v for k, v in params_mapping.items() if v is not None})
|
|
96
|
+
if self.client_params:
|
|
97
|
+
_client_params.update(self.client_params)
|
|
98
|
+
return _client_params
|
|
48
99
|
|
|
49
100
|
def get_client(self) -> AzureOpenAIClient:
|
|
50
101
|
"""
|
|
@@ -54,12 +105,25 @@ class AzureOpenAI(OpenAILike):
|
|
|
54
105
|
AzureOpenAIClient: The OpenAI client.
|
|
55
106
|
|
|
56
107
|
"""
|
|
57
|
-
if self.
|
|
58
|
-
return self.
|
|
108
|
+
if self.client is not None and not self.client.is_closed():
|
|
109
|
+
return self.client
|
|
59
110
|
|
|
60
111
|
_client_params: Dict[str, Any] = self._get_client_params()
|
|
61
112
|
|
|
62
|
-
|
|
113
|
+
if self.http_client:
|
|
114
|
+
if isinstance(self.http_client, httpx.Client):
|
|
115
|
+
_client_params["http_client"] = self.http_client
|
|
116
|
+
else:
|
|
117
|
+
log_warning("http_client is not an instance of httpx.Client. Using default global httpx.Client.")
|
|
118
|
+
# Use global sync client when user http_client is invalid
|
|
119
|
+
_client_params["http_client"] = get_default_sync_client()
|
|
120
|
+
else:
|
|
121
|
+
# Use global sync client when no custom http_client is provided
|
|
122
|
+
_client_params["http_client"] = get_default_sync_client()
|
|
123
|
+
|
|
124
|
+
# Create client
|
|
125
|
+
self.client = AzureOpenAIClient(**_client_params)
|
|
126
|
+
return self.client
|
|
63
127
|
|
|
64
128
|
def get_async_client(self) -> AsyncAzureOpenAIClient:
|
|
65
129
|
"""
|
|
@@ -68,38 +132,23 @@ class AzureOpenAI(OpenAILike):
|
|
|
68
132
|
Returns:
|
|
69
133
|
AsyncAzureOpenAIClient: An instance of the asynchronous OpenAI client.
|
|
70
134
|
"""
|
|
135
|
+
if self.async_client and not self.async_client.is_closed():
|
|
136
|
+
return self.async_client
|
|
71
137
|
|
|
72
138
|
_client_params: Dict[str, Any] = self._get_client_params()
|
|
73
139
|
|
|
74
140
|
if self.http_client:
|
|
75
|
-
|
|
141
|
+
if isinstance(self.http_client, httpx.AsyncClient):
|
|
142
|
+
_client_params["http_client"] = self.http_client
|
|
143
|
+
else:
|
|
144
|
+
log_warning(
|
|
145
|
+
"http_client is not an instance of httpx.AsyncClient. Using default global httpx.AsyncClient."
|
|
146
|
+
)
|
|
147
|
+
# Use global async client when user http_client is invalid
|
|
148
|
+
_client_params["http_client"] = get_default_async_client()
|
|
76
149
|
else:
|
|
77
|
-
#
|
|
78
|
-
_client_params["http_client"] =
|
|
79
|
-
limits=httpx.Limits(max_connections=1000, max_keepalive_connections=100)
|
|
80
|
-
)
|
|
81
|
-
return AsyncAzureOpenAIClient(**_client_params)
|
|
150
|
+
# Use global async client when no custom http_client is provided
|
|
151
|
+
_client_params["http_client"] = get_default_async_client()
|
|
82
152
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if self.api_key:
|
|
86
|
-
_client_params["api_key"] = self.api_key
|
|
87
|
-
if self.api_version:
|
|
88
|
-
_client_params["api_version"] = self.api_version
|
|
89
|
-
if self.organization:
|
|
90
|
-
_client_params["organization"] = self.organization
|
|
91
|
-
if self.azure_endpoint:
|
|
92
|
-
_client_params["azure_endpoint"] = self.azure_endpoint
|
|
93
|
-
if self.azure_deployment:
|
|
94
|
-
_client_params["azure_deployment"] = self.azure_deployment
|
|
95
|
-
if self.base_url:
|
|
96
|
-
_client_params["base_url"] = self.base_url
|
|
97
|
-
if self.azure_ad_token:
|
|
98
|
-
_client_params["azure_ad_token"] = self.azure_ad_token
|
|
99
|
-
if self.azure_ad_token_provider:
|
|
100
|
-
_client_params["azure_ad_token_provider"] = self.azure_ad_token_provider
|
|
101
|
-
if self.http_client:
|
|
102
|
-
_client_params["http_client"] = self.http_client
|
|
103
|
-
if self.client_params:
|
|
104
|
-
_client_params.update(self.client_params)
|
|
105
|
-
return _client_params
|
|
153
|
+
self.async_client = AsyncAzureOpenAIClient(**_client_params)
|
|
154
|
+
return self.async_client
|