agno 2.2.13__py3-none-any.whl → 2.4.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agno/agent/__init__.py +6 -0
- agno/agent/agent.py +5252 -3145
- agno/agent/remote.py +525 -0
- agno/api/api.py +2 -0
- agno/client/__init__.py +3 -0
- agno/client/a2a/__init__.py +10 -0
- agno/client/a2a/client.py +554 -0
- agno/client/a2a/schemas.py +112 -0
- agno/client/a2a/utils.py +369 -0
- agno/client/os.py +2669 -0
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/manager.py +2 -2
- agno/db/base.py +927 -6
- agno/db/dynamo/dynamo.py +788 -2
- agno/db/dynamo/schemas.py +128 -0
- agno/db/dynamo/utils.py +26 -3
- agno/db/firestore/firestore.py +674 -50
- agno/db/firestore/schemas.py +41 -0
- agno/db/firestore/utils.py +25 -10
- agno/db/gcs_json/gcs_json_db.py +506 -3
- agno/db/gcs_json/utils.py +14 -2
- agno/db/in_memory/in_memory_db.py +203 -4
- agno/db/in_memory/utils.py +14 -2
- agno/db/json/json_db.py +498 -2
- agno/db/json/utils.py +14 -2
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/utils.py +19 -0
- agno/db/migrations/v1_to_v2.py +54 -16
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +977 -0
- agno/db/mongo/async_mongo.py +1013 -39
- agno/db/mongo/mongo.py +684 -4
- agno/db/mongo/schemas.py +48 -0
- agno/db/mongo/utils.py +17 -0
- agno/db/mysql/__init__.py +2 -1
- agno/db/mysql/async_mysql.py +2958 -0
- agno/db/mysql/mysql.py +722 -53
- agno/db/mysql/schemas.py +77 -11
- agno/db/mysql/utils.py +151 -8
- agno/db/postgres/async_postgres.py +1254 -137
- agno/db/postgres/postgres.py +2316 -93
- agno/db/postgres/schemas.py +153 -21
- agno/db/postgres/utils.py +22 -7
- agno/db/redis/redis.py +531 -3
- agno/db/redis/schemas.py +36 -0
- agno/db/redis/utils.py +31 -15
- agno/db/schemas/evals.py +1 -0
- agno/db/schemas/memory.py +20 -9
- agno/db/singlestore/schemas.py +70 -1
- agno/db/singlestore/singlestore.py +737 -74
- agno/db/singlestore/utils.py +13 -3
- agno/db/sqlite/async_sqlite.py +1069 -89
- agno/db/sqlite/schemas.py +133 -1
- agno/db/sqlite/sqlite.py +2203 -165
- agno/db/sqlite/utils.py +21 -11
- agno/db/surrealdb/models.py +25 -0
- agno/db/surrealdb/surrealdb.py +603 -1
- agno/db/utils.py +60 -0
- agno/eval/__init__.py +26 -3
- agno/eval/accuracy.py +25 -12
- agno/eval/agent_as_judge.py +871 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +10 -4
- agno/eval/reliability.py +22 -13
- agno/eval/utils.py +2 -1
- agno/exceptions.py +42 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/client.py +13 -2
- agno/knowledge/__init__.py +4 -0
- agno/knowledge/chunking/code.py +90 -0
- agno/knowledge/chunking/document.py +65 -4
- agno/knowledge/chunking/fixed.py +4 -1
- agno/knowledge/chunking/markdown.py +102 -11
- agno/knowledge/chunking/recursive.py +2 -2
- agno/knowledge/chunking/semantic.py +130 -48
- agno/knowledge/chunking/strategy.py +18 -0
- agno/knowledge/embedder/azure_openai.py +0 -1
- agno/knowledge/embedder/google.py +1 -1
- agno/knowledge/embedder/mistral.py +1 -1
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/openai.py +16 -12
- agno/knowledge/filesystem.py +412 -0
- agno/knowledge/knowledge.py +4261 -1199
- agno/knowledge/protocol.py +134 -0
- agno/knowledge/reader/arxiv_reader.py +3 -2
- agno/knowledge/reader/base.py +9 -7
- agno/knowledge/reader/csv_reader.py +91 -42
- agno/knowledge/reader/docx_reader.py +9 -10
- agno/knowledge/reader/excel_reader.py +225 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +38 -48
- agno/knowledge/reader/firecrawl_reader.py +3 -2
- agno/knowledge/reader/json_reader.py +16 -22
- agno/knowledge/reader/markdown_reader.py +15 -14
- agno/knowledge/reader/pdf_reader.py +33 -28
- agno/knowledge/reader/pptx_reader.py +9 -10
- agno/knowledge/reader/reader_factory.py +135 -1
- agno/knowledge/reader/s3_reader.py +8 -16
- agno/knowledge/reader/tavily_reader.py +3 -3
- agno/knowledge/reader/text_reader.py +15 -14
- agno/knowledge/reader/utils/__init__.py +17 -0
- agno/knowledge/reader/utils/spreadsheet.py +114 -0
- agno/knowledge/reader/web_search_reader.py +8 -65
- agno/knowledge/reader/website_reader.py +16 -13
- agno/knowledge/reader/wikipedia_reader.py +36 -3
- agno/knowledge/reader/youtube_reader.py +3 -2
- agno/knowledge/remote_content/__init__.py +33 -0
- agno/knowledge/remote_content/config.py +266 -0
- agno/knowledge/remote_content/remote_content.py +105 -17
- agno/knowledge/utils.py +76 -22
- agno/learn/__init__.py +71 -0
- agno/learn/config.py +463 -0
- agno/learn/curate.py +185 -0
- agno/learn/machine.py +725 -0
- agno/learn/schemas.py +1114 -0
- agno/learn/stores/__init__.py +38 -0
- agno/learn/stores/decision_log.py +1156 -0
- agno/learn/stores/entity_memory.py +3275 -0
- agno/learn/stores/learned_knowledge.py +1583 -0
- agno/learn/stores/protocol.py +117 -0
- agno/learn/stores/session_context.py +1217 -0
- agno/learn/stores/user_memory.py +1495 -0
- agno/learn/stores/user_profile.py +1220 -0
- agno/learn/utils.py +209 -0
- agno/media.py +22 -6
- agno/memory/__init__.py +14 -1
- agno/memory/manager.py +223 -8
- agno/memory/strategies/__init__.py +15 -0
- agno/memory/strategies/base.py +66 -0
- agno/memory/strategies/summarize.py +196 -0
- agno/memory/strategies/types.py +37 -0
- agno/models/aimlapi/aimlapi.py +17 -0
- agno/models/anthropic/claude.py +434 -59
- agno/models/aws/bedrock.py +121 -20
- agno/models/aws/claude.py +131 -274
- agno/models/azure/ai_foundry.py +10 -6
- agno/models/azure/openai_chat.py +33 -10
- agno/models/base.py +1162 -561
- agno/models/cerebras/cerebras.py +120 -24
- agno/models/cerebras/cerebras_openai.py +21 -2
- agno/models/cohere/chat.py +65 -6
- agno/models/cometapi/cometapi.py +18 -1
- agno/models/dashscope/dashscope.py +2 -3
- agno/models/deepinfra/deepinfra.py +18 -1
- agno/models/deepseek/deepseek.py +69 -3
- agno/models/fireworks/fireworks.py +18 -1
- agno/models/google/gemini.py +959 -89
- agno/models/google/utils.py +22 -0
- agno/models/groq/groq.py +48 -18
- agno/models/huggingface/huggingface.py +17 -6
- agno/models/ibm/watsonx.py +16 -6
- agno/models/internlm/internlm.py +18 -1
- agno/models/langdb/langdb.py +13 -1
- agno/models/litellm/chat.py +88 -9
- agno/models/litellm/litellm_openai.py +18 -1
- agno/models/message.py +24 -5
- agno/models/meta/llama.py +40 -13
- agno/models/meta/llama_openai.py +22 -21
- agno/models/metrics.py +12 -0
- agno/models/mistral/mistral.py +8 -4
- agno/models/n1n/__init__.py +3 -0
- agno/models/n1n/n1n.py +57 -0
- agno/models/nebius/nebius.py +6 -7
- agno/models/nvidia/nvidia.py +20 -3
- agno/models/ollama/__init__.py +2 -0
- agno/models/ollama/chat.py +17 -6
- agno/models/ollama/responses.py +100 -0
- agno/models/openai/__init__.py +2 -0
- agno/models/openai/chat.py +117 -26
- agno/models/openai/open_responses.py +46 -0
- agno/models/openai/responses.py +110 -32
- agno/models/openrouter/__init__.py +2 -0
- agno/models/openrouter/openrouter.py +67 -2
- agno/models/openrouter/responses.py +146 -0
- agno/models/perplexity/perplexity.py +19 -1
- agno/models/portkey/portkey.py +7 -6
- agno/models/requesty/requesty.py +19 -2
- agno/models/response.py +20 -2
- agno/models/sambanova/sambanova.py +20 -3
- agno/models/siliconflow/siliconflow.py +19 -2
- agno/models/together/together.py +20 -3
- agno/models/vercel/v0.py +20 -3
- agno/models/vertexai/claude.py +124 -4
- agno/models/vllm/vllm.py +19 -14
- agno/models/xai/xai.py +19 -2
- agno/os/app.py +467 -137
- agno/os/auth.py +253 -5
- agno/os/config.py +22 -0
- agno/os/interfaces/a2a/a2a.py +7 -6
- agno/os/interfaces/a2a/router.py +635 -26
- agno/os/interfaces/a2a/utils.py +32 -33
- agno/os/interfaces/agui/agui.py +5 -3
- agno/os/interfaces/agui/router.py +26 -16
- agno/os/interfaces/agui/utils.py +97 -57
- agno/os/interfaces/base.py +7 -7
- agno/os/interfaces/slack/router.py +16 -7
- agno/os/interfaces/slack/slack.py +7 -7
- agno/os/interfaces/whatsapp/router.py +35 -7
- agno/os/interfaces/whatsapp/security.py +3 -1
- agno/os/interfaces/whatsapp/whatsapp.py +11 -8
- agno/os/managers.py +326 -0
- agno/os/mcp.py +652 -79
- agno/os/middleware/__init__.py +4 -0
- agno/os/middleware/jwt.py +718 -115
- agno/os/middleware/trailing_slash.py +27 -0
- agno/os/router.py +105 -1558
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +655 -0
- agno/os/routers/agents/schema.py +288 -0
- agno/os/routers/components/__init__.py +3 -0
- agno/os/routers/components/components.py +475 -0
- agno/os/routers/database.py +155 -0
- agno/os/routers/evals/evals.py +111 -18
- agno/os/routers/evals/schemas.py +38 -5
- agno/os/routers/evals/utils.py +80 -11
- agno/os/routers/health.py +3 -3
- agno/os/routers/knowledge/knowledge.py +284 -35
- agno/os/routers/knowledge/schemas.py +14 -2
- agno/os/routers/memory/memory.py +274 -11
- agno/os/routers/memory/schemas.py +44 -3
- agno/os/routers/metrics/metrics.py +30 -15
- agno/os/routers/metrics/schemas.py +10 -6
- agno/os/routers/registry/__init__.py +3 -0
- agno/os/routers/registry/registry.py +337 -0
- agno/os/routers/session/session.py +143 -14
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +550 -0
- agno/os/routers/teams/schema.py +280 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +549 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +757 -0
- agno/os/routers/workflows/schema.py +139 -0
- agno/os/schema.py +157 -584
- agno/os/scopes.py +469 -0
- agno/os/settings.py +3 -0
- agno/os/utils.py +574 -185
- agno/reasoning/anthropic.py +85 -1
- agno/reasoning/azure_ai_foundry.py +93 -1
- agno/reasoning/deepseek.py +102 -2
- agno/reasoning/default.py +6 -7
- agno/reasoning/gemini.py +87 -3
- agno/reasoning/groq.py +109 -2
- agno/reasoning/helpers.py +6 -7
- agno/reasoning/manager.py +1238 -0
- agno/reasoning/ollama.py +93 -1
- agno/reasoning/openai.py +115 -1
- agno/reasoning/vertexai.py +85 -1
- agno/registry/__init__.py +3 -0
- agno/registry/registry.py +68 -0
- agno/remote/__init__.py +3 -0
- agno/remote/base.py +581 -0
- agno/run/__init__.py +2 -4
- agno/run/agent.py +134 -19
- agno/run/base.py +49 -1
- agno/run/cancel.py +65 -52
- agno/run/cancellation_management/__init__.py +9 -0
- agno/run/cancellation_management/base.py +78 -0
- agno/run/cancellation_management/in_memory_cancellation_manager.py +100 -0
- agno/run/cancellation_management/redis_cancellation_manager.py +236 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +111 -19
- agno/run/workflow.py +2 -1
- agno/session/agent.py +57 -92
- agno/session/summary.py +1 -1
- agno/session/team.py +62 -115
- agno/session/workflow.py +353 -57
- agno/skills/__init__.py +17 -0
- agno/skills/agent_skills.py +377 -0
- agno/skills/errors.py +32 -0
- agno/skills/loaders/__init__.py +4 -0
- agno/skills/loaders/base.py +27 -0
- agno/skills/loaders/local.py +216 -0
- agno/skills/skill.py +65 -0
- agno/skills/utils.py +107 -0
- agno/skills/validator.py +277 -0
- agno/table.py +10 -0
- agno/team/__init__.py +5 -1
- agno/team/remote.py +447 -0
- agno/team/team.py +3769 -2202
- agno/tools/brandfetch.py +27 -18
- agno/tools/browserbase.py +225 -16
- agno/tools/crawl4ai.py +3 -0
- agno/tools/duckduckgo.py +25 -71
- agno/tools/exa.py +0 -21
- agno/tools/file.py +14 -13
- agno/tools/file_generation.py +12 -6
- agno/tools/firecrawl.py +15 -7
- agno/tools/function.py +94 -113
- agno/tools/google_bigquery.py +11 -2
- agno/tools/google_drive.py +4 -3
- agno/tools/knowledge.py +9 -4
- agno/tools/mcp/mcp.py +301 -18
- agno/tools/mcp/multi_mcp.py +269 -14
- agno/tools/mem0.py +11 -10
- agno/tools/memory.py +47 -46
- agno/tools/mlx_transcribe.py +10 -7
- agno/tools/models/nebius.py +5 -5
- agno/tools/models_labs.py +20 -10
- agno/tools/nano_banana.py +151 -0
- agno/tools/parallel.py +0 -7
- agno/tools/postgres.py +76 -36
- agno/tools/python.py +14 -6
- agno/tools/reasoning.py +30 -23
- agno/tools/redshift.py +406 -0
- agno/tools/shopify.py +1519 -0
- agno/tools/spotify.py +919 -0
- agno/tools/tavily.py +4 -1
- agno/tools/toolkit.py +253 -18
- agno/tools/websearch.py +93 -0
- agno/tools/website.py +1 -1
- agno/tools/wikipedia.py +1 -1
- agno/tools/workflow.py +56 -48
- agno/tools/yfinance.py +12 -11
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +161 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +112 -0
- agno/utils/agent.py +251 -10
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +264 -7
- agno/utils/hooks.py +111 -3
- agno/utils/http.py +161 -2
- agno/utils/mcp.py +49 -8
- agno/utils/media.py +22 -1
- agno/utils/models/ai_foundry.py +9 -2
- agno/utils/models/claude.py +20 -5
- agno/utils/models/cohere.py +9 -2
- agno/utils/models/llama.py +9 -2
- agno/utils/models/mistral.py +4 -2
- agno/utils/os.py +0 -0
- agno/utils/print_response/agent.py +99 -16
- agno/utils/print_response/team.py +223 -24
- agno/utils/print_response/workflow.py +0 -2
- agno/utils/prompts.py +8 -6
- agno/utils/remote.py +23 -0
- agno/utils/response.py +1 -13
- agno/utils/string.py +91 -2
- agno/utils/team.py +62 -12
- agno/utils/tokens.py +657 -0
- agno/vectordb/base.py +15 -2
- agno/vectordb/cassandra/cassandra.py +1 -1
- agno/vectordb/chroma/__init__.py +2 -1
- agno/vectordb/chroma/chromadb.py +468 -23
- agno/vectordb/clickhouse/clickhousedb.py +1 -1
- agno/vectordb/couchbase/couchbase.py +6 -2
- agno/vectordb/lancedb/lance_db.py +7 -38
- agno/vectordb/lightrag/lightrag.py +7 -6
- agno/vectordb/milvus/milvus.py +118 -84
- agno/vectordb/mongodb/__init__.py +2 -1
- agno/vectordb/mongodb/mongodb.py +14 -31
- agno/vectordb/pgvector/pgvector.py +120 -66
- agno/vectordb/pineconedb/pineconedb.py +2 -19
- agno/vectordb/qdrant/__init__.py +2 -1
- agno/vectordb/qdrant/qdrant.py +33 -56
- agno/vectordb/redis/__init__.py +2 -1
- agno/vectordb/redis/redisdb.py +19 -31
- agno/vectordb/singlestore/singlestore.py +17 -9
- agno/vectordb/surrealdb/surrealdb.py +2 -38
- agno/vectordb/weaviate/__init__.py +2 -1
- agno/vectordb/weaviate/weaviate.py +7 -3
- agno/workflow/__init__.py +5 -1
- agno/workflow/agent.py +2 -2
- agno/workflow/condition.py +12 -10
- agno/workflow/loop.py +28 -9
- agno/workflow/parallel.py +21 -13
- agno/workflow/remote.py +362 -0
- agno/workflow/router.py +12 -9
- agno/workflow/step.py +261 -36
- agno/workflow/steps.py +12 -8
- agno/workflow/types.py +40 -77
- agno/workflow/workflow.py +939 -213
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/METADATA +134 -181
- agno-2.4.3.dist-info/RECORD +677 -0
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/WHEEL +1 -1
- agno/tools/googlesearch.py +0 -98
- agno/tools/memori.py +0 -339
- agno-2.2.13.dist-info/RECORD +0 -575
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/top_level.txt +0 -0
agno/models/aws/claude.py
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
from os import getenv
|
|
3
|
-
from typing import Any,
|
|
3
|
+
from typing import Any, Dict, List, Optional, Type, Union
|
|
4
4
|
|
|
5
|
+
import httpx
|
|
5
6
|
from pydantic import BaseModel
|
|
6
7
|
|
|
7
|
-
from agno.exceptions import ModelProviderError, ModelRateLimitError
|
|
8
8
|
from agno.models.anthropic import Claude as AnthropicClaude
|
|
9
|
-
from agno.
|
|
10
|
-
from agno.
|
|
11
|
-
from agno.
|
|
12
|
-
from agno.utils.log import log_debug, log_error, log_warning
|
|
13
|
-
from agno.utils.models.claude import format_messages
|
|
9
|
+
from agno.utils.http import get_default_async_client, get_default_sync_client
|
|
10
|
+
from agno.utils.log import log_debug, log_warning
|
|
11
|
+
from agno.utils.models.claude import format_tools_for_model
|
|
14
12
|
|
|
15
13
|
try:
|
|
16
|
-
from anthropic import AnthropicBedrock,
|
|
14
|
+
from anthropic import AnthropicBedrock, AsyncAnthropicBedrock
|
|
17
15
|
except ImportError:
|
|
18
16
|
raise ImportError("`anthropic[bedrock]` not installed. Please install using `pip install anthropic[bedrock]`")
|
|
19
17
|
|
|
@@ -31,44 +29,69 @@ class Claude(AnthropicClaude):
|
|
|
31
29
|
For more information, see: https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic.html
|
|
32
30
|
"""
|
|
33
31
|
|
|
34
|
-
id: str = "anthropic.claude-
|
|
32
|
+
id: str = "global.anthropic.claude-sonnet-4-5-20250929-v1:0"
|
|
35
33
|
name: str = "AwsBedrockAnthropicClaude"
|
|
36
34
|
provider: str = "AwsBedrock"
|
|
37
35
|
|
|
38
36
|
aws_access_key: Optional[str] = None
|
|
39
37
|
aws_secret_key: Optional[str] = None
|
|
40
38
|
aws_region: Optional[str] = None
|
|
39
|
+
api_key: Optional[str] = None
|
|
41
40
|
session: Optional[Session] = None
|
|
42
41
|
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
temperature: Optional[float] = None
|
|
46
|
-
top_p: Optional[float] = None
|
|
47
|
-
top_k: Optional[int] = None
|
|
48
|
-
stop_sequences: Optional[List[str]] = None
|
|
42
|
+
client: Optional[AnthropicBedrock] = None # type: ignore
|
|
43
|
+
async_client: Optional[AsyncAnthropicBedrock] = None # type: ignore
|
|
49
44
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
45
|
+
def __post_init__(self):
|
|
46
|
+
"""Validate model configuration after initialization"""
|
|
47
|
+
# Validate thinking support immediately at model creation
|
|
48
|
+
if self.thinking:
|
|
49
|
+
self._validate_thinking_support()
|
|
50
|
+
# Overwrite output schema support for AWS Bedrock Claude
|
|
51
|
+
self.supports_native_structured_outputs = False
|
|
52
|
+
self.supports_json_schema_outputs = False
|
|
54
53
|
|
|
55
|
-
def
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
def _get_client_params(self) -> Dict[str, Any]:
|
|
55
|
+
if self.session:
|
|
56
|
+
credentials = self.session.get_credentials()
|
|
57
|
+
client_params: Dict[str, Any] = {
|
|
58
|
+
"aws_access_key": credentials.access_key,
|
|
59
|
+
"aws_secret_key": credentials.secret_key,
|
|
60
|
+
"aws_session_token": credentials.token,
|
|
61
|
+
"aws_region": self.session.region_name,
|
|
62
|
+
}
|
|
63
|
+
else:
|
|
64
|
+
self.api_key = self.api_key or getenv("AWS_BEDROCK_API_KEY")
|
|
65
|
+
if self.api_key:
|
|
66
|
+
self.aws_region = self.aws_region or getenv("AWS_REGION")
|
|
67
|
+
client_params = {
|
|
68
|
+
"api_key": self.api_key,
|
|
69
|
+
}
|
|
70
|
+
if self.aws_region:
|
|
71
|
+
client_params["aws_region"] = self.aws_region
|
|
72
|
+
else:
|
|
73
|
+
self.aws_access_key = self.aws_access_key or getenv("AWS_ACCESS_KEY_ID") or getenv("AWS_ACCESS_KEY")
|
|
74
|
+
self.aws_secret_key = self.aws_secret_key or getenv("AWS_SECRET_ACCESS_KEY") or getenv("AWS_SECRET_KEY")
|
|
75
|
+
self.aws_region = self.aws_region or getenv("AWS_REGION")
|
|
76
|
+
|
|
77
|
+
client_params = {
|
|
78
|
+
"aws_secret_key": self.aws_secret_key,
|
|
79
|
+
"aws_access_key": self.aws_access_key,
|
|
80
|
+
"aws_region": self.aws_region,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if not (self.api_key or (self.aws_access_key and self.aws_secret_key)):
|
|
84
|
+
log_warning(
|
|
85
|
+
"AWS credentials not found. Please set AWS_BEDROCK_API_KEY or AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables or provide a boto3 session."
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
if self.timeout is not None:
|
|
89
|
+
client_params["timeout"] = self.timeout
|
|
58
90
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"""
|
|
62
|
-
_dict = super().to_dict()
|
|
63
|
-
_dict["max_tokens"] = self.max_tokens
|
|
64
|
-
_dict["temperature"] = self.temperature
|
|
65
|
-
_dict["top_p"] = self.top_p
|
|
66
|
-
_dict["top_k"] = self.top_k
|
|
67
|
-
_dict["stop_sequences"] = self.stop_sequences
|
|
68
|
-
return _dict
|
|
91
|
+
if self.client_params:
|
|
92
|
+
client_params.update(self.client_params)
|
|
69
93
|
|
|
70
|
-
|
|
71
|
-
async_client: Optional[AsyncAnthropicBedrock] = None # type: ignore
|
|
94
|
+
return client_params
|
|
72
95
|
|
|
73
96
|
def get_client(self):
|
|
74
97
|
"""
|
|
@@ -80,27 +103,18 @@ class Claude(AnthropicClaude):
|
|
|
80
103
|
if self.client is not None and not self.client.is_closed():
|
|
81
104
|
return self.client
|
|
82
105
|
|
|
83
|
-
|
|
84
|
-
credentials = self.session.get_credentials()
|
|
85
|
-
client_params = {
|
|
86
|
-
"aws_access_key": credentials.access_key,
|
|
87
|
-
"aws_secret_key": credentials.secret_key,
|
|
88
|
-
"aws_session_token": credentials.token,
|
|
89
|
-
"aws_region": self.session.region_name,
|
|
90
|
-
}
|
|
91
|
-
else:
|
|
92
|
-
self.aws_access_key = self.aws_access_key or getenv("AWS_ACCESS_KEY")
|
|
93
|
-
self.aws_secret_key = self.aws_secret_key or getenv("AWS_SECRET_KEY")
|
|
94
|
-
self.aws_region = self.aws_region or getenv("AWS_REGION")
|
|
95
|
-
|
|
96
|
-
client_params = {
|
|
97
|
-
"aws_secret_key": self.aws_secret_key,
|
|
98
|
-
"aws_access_key": self.aws_access_key,
|
|
99
|
-
"aws_region": self.aws_region,
|
|
100
|
-
}
|
|
106
|
+
client_params = self._get_client_params()
|
|
101
107
|
|
|
102
|
-
if self.
|
|
103
|
-
|
|
108
|
+
if self.http_client:
|
|
109
|
+
if isinstance(self.http_client, httpx.Client):
|
|
110
|
+
client_params["http_client"] = self.http_client
|
|
111
|
+
else:
|
|
112
|
+
log_warning("http_client is not an instance of httpx.Client. Using default global httpx.Client.")
|
|
113
|
+
# Use global sync client when user http_client is invalid
|
|
114
|
+
client_params["http_client"] = get_default_sync_client()
|
|
115
|
+
else:
|
|
116
|
+
# Use global sync client when no custom http_client is provided
|
|
117
|
+
client_params["http_client"] = get_default_sync_client()
|
|
104
118
|
|
|
105
119
|
self.client = AnthropicBedrock(
|
|
106
120
|
**client_params, # type: ignore
|
|
@@ -117,39 +131,46 @@ class Claude(AnthropicClaude):
|
|
|
117
131
|
if self.async_client is not None:
|
|
118
132
|
return self.async_client
|
|
119
133
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
"
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
134
|
+
client_params = self._get_client_params()
|
|
135
|
+
|
|
136
|
+
if self.http_client:
|
|
137
|
+
if isinstance(self.http_client, httpx.AsyncClient):
|
|
138
|
+
client_params["http_client"] = self.http_client
|
|
139
|
+
else:
|
|
140
|
+
log_warning(
|
|
141
|
+
"http_client is not an instance of httpx.AsyncClient. Using default global httpx.AsyncClient."
|
|
142
|
+
)
|
|
143
|
+
# Use global async client when user http_client is invalid
|
|
144
|
+
client_params["http_client"] = get_default_async_client()
|
|
128
145
|
else:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
"aws_access_key": self.aws_access_key,
|
|
132
|
-
"aws_region": self.aws_region,
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if self.client_params:
|
|
136
|
-
client_params.update(self.client_params)
|
|
146
|
+
# Use global async client when no custom http_client is provided
|
|
147
|
+
client_params["http_client"] = get_default_async_client()
|
|
137
148
|
|
|
138
149
|
self.async_client = AsyncAnthropicBedrock(
|
|
139
150
|
**client_params, # type: ignore
|
|
140
151
|
)
|
|
141
152
|
return self.async_client
|
|
142
153
|
|
|
143
|
-
def get_request_params(
|
|
154
|
+
def get_request_params(
|
|
155
|
+
self,
|
|
156
|
+
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
157
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
158
|
+
) -> Dict[str, Any]:
|
|
144
159
|
"""
|
|
145
160
|
Generate keyword arguments for API requests.
|
|
146
161
|
|
|
147
162
|
Returns:
|
|
148
163
|
Dict[str, Any]: The keyword arguments for API requests.
|
|
149
164
|
"""
|
|
165
|
+
# Validate thinking support if thinking is enabled
|
|
166
|
+
if self.thinking:
|
|
167
|
+
self._validate_thinking_support()
|
|
168
|
+
|
|
150
169
|
_request_params: Dict[str, Any] = {}
|
|
151
170
|
if self.max_tokens:
|
|
152
171
|
_request_params["max_tokens"] = self.max_tokens
|
|
172
|
+
if self.thinking:
|
|
173
|
+
_request_params["thinking"] = self.thinking
|
|
153
174
|
if self.temperature:
|
|
154
175
|
_request_params["temperature"] = self.temperature
|
|
155
176
|
if self.stop_sequences:
|
|
@@ -158,6 +179,16 @@ class Claude(AnthropicClaude):
|
|
|
158
179
|
_request_params["top_p"] = self.top_p
|
|
159
180
|
if self.top_k:
|
|
160
181
|
_request_params["top_k"] = self.top_k
|
|
182
|
+
if self.timeout:
|
|
183
|
+
_request_params["timeout"] = self.timeout
|
|
184
|
+
|
|
185
|
+
# Build betas list - include existing betas and add new one if needed
|
|
186
|
+
betas_list = list(self.betas) if self.betas else []
|
|
187
|
+
|
|
188
|
+
# Include betas if any are present
|
|
189
|
+
if betas_list:
|
|
190
|
+
_request_params["betas"] = betas_list
|
|
191
|
+
|
|
161
192
|
if self.request_params:
|
|
162
193
|
_request_params.update(self.request_params)
|
|
163
194
|
|
|
@@ -165,214 +196,40 @@ class Claude(AnthropicClaude):
|
|
|
165
196
|
log_debug(f"Calling {self.provider} with request parameters: {_request_params}", log_level=2)
|
|
166
197
|
return _request_params
|
|
167
198
|
|
|
168
|
-
def
|
|
169
|
-
self,
|
|
170
|
-
messages: List[Message],
|
|
171
|
-
assistant_message: Message,
|
|
172
|
-
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
173
|
-
tools: Optional[List[Dict[str, Any]]] = None,
|
|
174
|
-
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
175
|
-
run_response: Optional[RunOutput] = None,
|
|
176
|
-
) -> ModelResponse:
|
|
177
|
-
"""
|
|
178
|
-
Send a request to the Anthropic API to generate a response.
|
|
179
|
-
"""
|
|
180
|
-
|
|
181
|
-
try:
|
|
182
|
-
chat_messages, system_message = format_messages(messages)
|
|
183
|
-
request_kwargs = self._prepare_request_kwargs(system_message, tools)
|
|
184
|
-
|
|
185
|
-
if run_response and run_response.metrics:
|
|
186
|
-
run_response.metrics.set_time_to_first_token()
|
|
187
|
-
|
|
188
|
-
assistant_message.metrics.start_timer()
|
|
189
|
-
response = self.get_client().messages.create(
|
|
190
|
-
model=self.id,
|
|
191
|
-
messages=chat_messages, # type: ignore
|
|
192
|
-
**request_kwargs,
|
|
193
|
-
)
|
|
194
|
-
assistant_message.metrics.stop_timer()
|
|
195
|
-
|
|
196
|
-
model_response = self._parse_provider_response(response, response_format=response_format)
|
|
197
|
-
|
|
198
|
-
return model_response
|
|
199
|
-
|
|
200
|
-
except APIConnectionError as e:
|
|
201
|
-
log_error(f"Connection error while calling Claude API: {str(e)}")
|
|
202
|
-
raise ModelProviderError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
203
|
-
except RateLimitError as e:
|
|
204
|
-
log_warning(f"Rate limit exceeded: {str(e)}")
|
|
205
|
-
raise ModelRateLimitError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
206
|
-
except APIStatusError as e:
|
|
207
|
-
log_error(f"Claude API error (status {e.status_code}): {str(e)}")
|
|
208
|
-
raise ModelProviderError(
|
|
209
|
-
message=e.message, status_code=e.status_code, model_name=self.name, model_id=self.id
|
|
210
|
-
) from e
|
|
211
|
-
except Exception as e:
|
|
212
|
-
log_error(f"Unexpected error calling Claude API: {str(e)}")
|
|
213
|
-
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
214
|
-
|
|
215
|
-
def invoke_stream(
|
|
216
|
-
self,
|
|
217
|
-
messages: List[Message],
|
|
218
|
-
assistant_message: Message,
|
|
219
|
-
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
220
|
-
tools: Optional[List[Dict[str, Any]]] = None,
|
|
221
|
-
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
222
|
-
run_response: Optional[RunOutput] = None,
|
|
223
|
-
) -> Iterator[ModelResponse]:
|
|
224
|
-
"""
|
|
225
|
-
Stream a response from the Anthropic API.
|
|
226
|
-
|
|
227
|
-
Args:
|
|
228
|
-
messages (List[Message]): A list of messages to send to the model.
|
|
229
|
-
|
|
230
|
-
Returns:
|
|
231
|
-
Any: The streamed response from the model.
|
|
232
|
-
|
|
233
|
-
Raises:
|
|
234
|
-
APIConnectionError: If there are network connectivity issues
|
|
235
|
-
RateLimitError: If the API rate limit is exceeded
|
|
236
|
-
APIStatusError: For other API-related errors
|
|
237
|
-
"""
|
|
238
|
-
|
|
239
|
-
chat_messages, system_message = format_messages(messages)
|
|
240
|
-
request_kwargs = self._prepare_request_kwargs(system_message, tools)
|
|
241
|
-
|
|
242
|
-
try:
|
|
243
|
-
if run_response and run_response.metrics:
|
|
244
|
-
run_response.metrics.set_time_to_first_token()
|
|
245
|
-
|
|
246
|
-
assistant_message.metrics.start_timer()
|
|
247
|
-
|
|
248
|
-
with self.get_client().messages.stream(
|
|
249
|
-
model=self.id,
|
|
250
|
-
messages=chat_messages, # type: ignore
|
|
251
|
-
**request_kwargs,
|
|
252
|
-
) as stream:
|
|
253
|
-
for chunk in stream:
|
|
254
|
-
yield self._parse_provider_response_delta(chunk)
|
|
255
|
-
|
|
256
|
-
assistant_message.metrics.stop_timer()
|
|
257
|
-
|
|
258
|
-
except APIConnectionError as e:
|
|
259
|
-
log_error(f"Connection error while calling Claude API: {str(e)}")
|
|
260
|
-
raise ModelProviderError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
261
|
-
except RateLimitError as e:
|
|
262
|
-
log_warning(f"Rate limit exceeded: {str(e)}")
|
|
263
|
-
raise ModelRateLimitError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
264
|
-
except APIStatusError as e:
|
|
265
|
-
log_error(f"Claude API error (status {e.status_code}): {str(e)}")
|
|
266
|
-
raise ModelProviderError(
|
|
267
|
-
message=e.message, status_code=e.status_code, model_name=self.name, model_id=self.id
|
|
268
|
-
) from e
|
|
269
|
-
except Exception as e:
|
|
270
|
-
log_error(f"Unexpected error calling Claude API: {str(e)}")
|
|
271
|
-
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
272
|
-
|
|
273
|
-
async def ainvoke(
|
|
199
|
+
def _prepare_request_kwargs(
|
|
274
200
|
self,
|
|
275
|
-
|
|
276
|
-
assistant_message: Message,
|
|
277
|
-
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
201
|
+
system_message: str,
|
|
278
202
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
279
|
-
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
280
|
-
run_response: Optional[RunOutput] = None,
|
|
281
|
-
) -> ModelResponse:
|
|
282
|
-
"""
|
|
283
|
-
Send an asynchronous request to the Anthropic API to generate a response.
|
|
284
|
-
"""
|
|
285
|
-
|
|
286
|
-
try:
|
|
287
|
-
chat_messages, system_message = format_messages(messages)
|
|
288
|
-
request_kwargs = self._prepare_request_kwargs(system_message, tools)
|
|
289
|
-
|
|
290
|
-
if run_response and run_response.metrics:
|
|
291
|
-
run_response.metrics.set_time_to_first_token()
|
|
292
|
-
|
|
293
|
-
assistant_message.metrics.start_timer()
|
|
294
|
-
|
|
295
|
-
response = await self.get_async_client().messages.create(
|
|
296
|
-
model=self.id,
|
|
297
|
-
messages=chat_messages, # type: ignore
|
|
298
|
-
**request_kwargs,
|
|
299
|
-
)
|
|
300
|
-
|
|
301
|
-
assistant_message.metrics.stop_timer()
|
|
302
|
-
|
|
303
|
-
model_response = self._parse_provider_response(response, response_format=response_format)
|
|
304
|
-
|
|
305
|
-
return model_response
|
|
306
|
-
|
|
307
|
-
except APIConnectionError as e:
|
|
308
|
-
log_error(f"Connection error while calling Claude API: {str(e)}")
|
|
309
|
-
raise ModelProviderError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
310
|
-
except RateLimitError as e:
|
|
311
|
-
log_warning(f"Rate limit exceeded: {str(e)}")
|
|
312
|
-
raise ModelRateLimitError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
313
|
-
except APIStatusError as e:
|
|
314
|
-
log_error(f"Claude API error (status {e.status_code}): {str(e)}")
|
|
315
|
-
raise ModelProviderError(
|
|
316
|
-
message=e.message, status_code=e.status_code, model_name=self.name, model_id=self.id
|
|
317
|
-
) from e
|
|
318
|
-
except Exception as e:
|
|
319
|
-
log_error(f"Unexpected error calling Claude API: {str(e)}")
|
|
320
|
-
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
321
|
-
|
|
322
|
-
async def ainvoke_stream(
|
|
323
|
-
self,
|
|
324
|
-
messages: List[Message],
|
|
325
|
-
assistant_message: Message,
|
|
326
203
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
327
|
-
|
|
328
|
-
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
329
|
-
run_response: Optional[RunOutput] = None,
|
|
330
|
-
) -> AsyncIterator[ModelResponse]:
|
|
204
|
+
) -> Dict[str, Any]:
|
|
331
205
|
"""
|
|
332
|
-
|
|
206
|
+
Prepare the request keyword arguments for the API call.
|
|
333
207
|
|
|
334
208
|
Args:
|
|
335
|
-
|
|
209
|
+
system_message (str): The concatenated system messages.
|
|
210
|
+
tools: Optional list of tools
|
|
211
|
+
response_format: Optional response format (Pydantic model or dict)
|
|
336
212
|
|
|
337
213
|
Returns:
|
|
338
|
-
Any: The
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
async for chunk in stream:
|
|
361
|
-
yield self._parse_provider_response_delta(chunk)
|
|
362
|
-
|
|
363
|
-
assistant_message.metrics.stop_timer()
|
|
364
|
-
|
|
365
|
-
except APIConnectionError as e:
|
|
366
|
-
log_error(f"Connection error while calling Claude API: {str(e)}")
|
|
367
|
-
raise ModelProviderError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
368
|
-
except RateLimitError as e:
|
|
369
|
-
log_warning(f"Rate limit exceeded: {str(e)}")
|
|
370
|
-
raise ModelRateLimitError(message=e.message, model_name=self.name, model_id=self.id) from e
|
|
371
|
-
except APIStatusError as e:
|
|
372
|
-
log_error(f"Claude API error (status {e.status_code}): {str(e)}")
|
|
373
|
-
raise ModelProviderError(
|
|
374
|
-
message=e.message, status_code=e.status_code, model_name=self.name, model_id=self.id
|
|
375
|
-
) from e
|
|
376
|
-
except Exception as e:
|
|
377
|
-
log_error(f"Unexpected error calling Claude API: {str(e)}")
|
|
378
|
-
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
214
|
+
Dict[str, Any]: The request keyword arguments.
|
|
215
|
+
"""
|
|
216
|
+
# Pass response_format and tools to get_request_params for beta header handling
|
|
217
|
+
request_kwargs = self.get_request_params(response_format=response_format, tools=tools).copy()
|
|
218
|
+
if system_message:
|
|
219
|
+
if self.cache_system_prompt:
|
|
220
|
+
cache_control = (
|
|
221
|
+
{"type": "ephemeral", "ttl": "1h"}
|
|
222
|
+
if self.extended_cache_time is not None and self.extended_cache_time is True
|
|
223
|
+
else {"type": "ephemeral"}
|
|
224
|
+
)
|
|
225
|
+
request_kwargs["system"] = [{"text": system_message, "type": "text", "cache_control": cache_control}]
|
|
226
|
+
else:
|
|
227
|
+
request_kwargs["system"] = [{"text": system_message, "type": "text"}]
|
|
228
|
+
|
|
229
|
+
# Format tools (this will handle strict mode)
|
|
230
|
+
if tools:
|
|
231
|
+
request_kwargs["tools"] = format_tools_for_model(tools)
|
|
232
|
+
|
|
233
|
+
if request_kwargs:
|
|
234
|
+
log_debug(f"Calling {self.provider} with request parameters: {request_kwargs}", log_level=2)
|
|
235
|
+
return request_kwargs
|
agno/models/azure/ai_foundry.py
CHANGED
|
@@ -136,9 +136,9 @@ class AzureAIFoundry(Model):
|
|
|
136
136
|
self.azure_endpoint = self.azure_endpoint or getenv("AZURE_ENDPOINT")
|
|
137
137
|
|
|
138
138
|
if not self.api_key:
|
|
139
|
-
|
|
139
|
+
log_error("AZURE_API_KEY not set. Please set the AZURE_API_KEY environment variable.")
|
|
140
140
|
if not self.azure_endpoint:
|
|
141
|
-
|
|
141
|
+
log_error("AZURE_ENDPOINT not set. Please set the AZURE_ENDPOINT environment variable.")
|
|
142
142
|
|
|
143
143
|
base_params = {
|
|
144
144
|
"endpoint": self.azure_endpoint,
|
|
@@ -207,6 +207,7 @@ class AzureAIFoundry(Model):
|
|
|
207
207
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
208
208
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
209
209
|
run_response: Optional[RunOutput] = None,
|
|
210
|
+
compress_tool_results: bool = False,
|
|
210
211
|
) -> ModelResponse:
|
|
211
212
|
"""
|
|
212
213
|
Send a chat completion request to the Azure AI API.
|
|
@@ -217,7 +218,7 @@ class AzureAIFoundry(Model):
|
|
|
217
218
|
|
|
218
219
|
assistant_message.metrics.start_timer()
|
|
219
220
|
provider_response = self.get_client().complete(
|
|
220
|
-
messages=[format_message(m) for m in messages],
|
|
221
|
+
messages=[format_message(m, compress_tool_results) for m in messages],
|
|
221
222
|
**self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
|
|
222
223
|
)
|
|
223
224
|
assistant_message.metrics.stop_timer()
|
|
@@ -246,6 +247,7 @@ class AzureAIFoundry(Model):
|
|
|
246
247
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
247
248
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
248
249
|
run_response: Optional[RunOutput] = None,
|
|
250
|
+
compress_tool_results: bool = False,
|
|
249
251
|
) -> ModelResponse:
|
|
250
252
|
"""
|
|
251
253
|
Sends an asynchronous chat completion request to the Azure AI API.
|
|
@@ -257,7 +259,7 @@ class AzureAIFoundry(Model):
|
|
|
257
259
|
|
|
258
260
|
assistant_message.metrics.start_timer()
|
|
259
261
|
provider_response = await self.get_async_client().complete(
|
|
260
|
-
messages=[format_message(m) for m in messages],
|
|
262
|
+
messages=[format_message(m, compress_tool_results) for m in messages],
|
|
261
263
|
**self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
|
|
262
264
|
)
|
|
263
265
|
assistant_message.metrics.stop_timer()
|
|
@@ -286,6 +288,7 @@ class AzureAIFoundry(Model):
|
|
|
286
288
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
287
289
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
288
290
|
run_response: Optional[RunOutput] = None,
|
|
291
|
+
compress_tool_results: bool = False,
|
|
289
292
|
) -> Iterator[ModelResponse]:
|
|
290
293
|
"""
|
|
291
294
|
Send a streaming chat completion request to the Azure AI API.
|
|
@@ -297,7 +300,7 @@ class AzureAIFoundry(Model):
|
|
|
297
300
|
assistant_message.metrics.start_timer()
|
|
298
301
|
|
|
299
302
|
for chunk in self.get_client().complete(
|
|
300
|
-
messages=[format_message(m) for m in messages],
|
|
303
|
+
messages=[format_message(m, compress_tool_results) for m in messages],
|
|
301
304
|
stream=True,
|
|
302
305
|
**self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
|
|
303
306
|
):
|
|
@@ -325,6 +328,7 @@ class AzureAIFoundry(Model):
|
|
|
325
328
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
326
329
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
327
330
|
run_response: Optional[RunOutput] = None,
|
|
331
|
+
compress_tool_results: bool = False,
|
|
328
332
|
) -> AsyncIterator[ModelResponse]:
|
|
329
333
|
"""
|
|
330
334
|
Sends an asynchronous streaming chat completion request to the Azure AI API.
|
|
@@ -336,7 +340,7 @@ class AzureAIFoundry(Model):
|
|
|
336
340
|
assistant_message.metrics.start_timer()
|
|
337
341
|
|
|
338
342
|
async_stream = await self.get_async_client().complete(
|
|
339
|
-
messages=[format_message(m) for m in messages],
|
|
343
|
+
messages=[format_message(m, compress_tool_results) for m in messages],
|
|
340
344
|
stream=True,
|
|
341
345
|
**self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
|
|
342
346
|
)
|
agno/models/azure/openai_chat.py
CHANGED
|
@@ -4,8 +4,10 @@ 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
|
|
8
|
-
from agno.utils.
|
|
9
|
+
from agno.utils.http import get_default_async_client, get_default_sync_client
|
|
10
|
+
from agno.utils.log import log_warning
|
|
9
11
|
|
|
10
12
|
try:
|
|
11
13
|
from openai import AsyncAzureOpenAI as AsyncAzureOpenAIClient
|
|
@@ -62,6 +64,19 @@ class AzureOpenAI(OpenAILike):
|
|
|
62
64
|
self.api_key = self.api_key or getenv("AZURE_OPENAI_API_KEY")
|
|
63
65
|
self.azure_endpoint = self.azure_endpoint or getenv("AZURE_OPENAI_ENDPOINT")
|
|
64
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
|
+
|
|
65
80
|
params_mapping = {
|
|
66
81
|
"api_key": self.api_key,
|
|
67
82
|
"api_version": self.api_version,
|
|
@@ -99,7 +114,12 @@ class AzureOpenAI(OpenAILike):
|
|
|
99
114
|
if isinstance(self.http_client, httpx.Client):
|
|
100
115
|
_client_params["http_client"] = self.http_client
|
|
101
116
|
else:
|
|
102
|
-
|
|
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()
|
|
103
123
|
|
|
104
124
|
# Create client
|
|
105
125
|
self.client = AzureOpenAIClient(**_client_params)
|
|
@@ -117,15 +137,18 @@ class AzureOpenAI(OpenAILike):
|
|
|
117
137
|
|
|
118
138
|
_client_params: Dict[str, Any] = self._get_client_params()
|
|
119
139
|
|
|
120
|
-
if self.http_client
|
|
121
|
-
|
|
140
|
+
if self.http_client:
|
|
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()
|
|
122
149
|
else:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
# Create a new async HTTP client with custom limits
|
|
126
|
-
_client_params["http_client"] = httpx.AsyncClient(
|
|
127
|
-
limits=httpx.Limits(max_connections=1000, max_keepalive_connections=100)
|
|
128
|
-
)
|
|
150
|
+
# Use global async client when no custom http_client is provided
|
|
151
|
+
_client_params["http_client"] = get_default_async_client()
|
|
129
152
|
|
|
130
153
|
self.async_client = AsyncAzureOpenAIClient(**_client_params)
|
|
131
154
|
return self.async_client
|