agno 2.0.0rc2__py3-none-any.whl → 2.3.0__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/agent.py +6009 -2874
- agno/api/api.py +2 -0
- agno/api/os.py +1 -1
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +385 -6
- agno/db/dynamo/dynamo.py +388 -81
- agno/db/dynamo/schemas.py +47 -10
- agno/db/dynamo/utils.py +63 -4
- agno/db/firestore/firestore.py +435 -64
- agno/db/firestore/schemas.py +11 -0
- agno/db/firestore/utils.py +102 -4
- agno/db/gcs_json/gcs_json_db.py +384 -42
- agno/db/gcs_json/utils.py +60 -26
- agno/db/in_memory/in_memory_db.py +351 -66
- agno/db/in_memory/utils.py +60 -2
- agno/db/json/json_db.py +339 -48
- agno/db/json/utils.py +60 -26
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +510 -37
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +15 -1
- agno/db/mongo/async_mongo.py +2036 -0
- agno/db/mongo/mongo.py +653 -76
- agno/db/mongo/schemas.py +13 -0
- agno/db/mongo/utils.py +80 -8
- agno/db/mysql/mysql.py +687 -25
- agno/db/mysql/schemas.py +61 -37
- agno/db/mysql/utils.py +60 -2
- agno/db/postgres/__init__.py +2 -1
- agno/db/postgres/async_postgres.py +2001 -0
- agno/db/postgres/postgres.py +676 -57
- agno/db/postgres/schemas.py +43 -18
- agno/db/postgres/utils.py +164 -2
- agno/db/redis/redis.py +344 -38
- agno/db/redis/schemas.py +18 -0
- agno/db/redis/utils.py +60 -2
- agno/db/schemas/__init__.py +2 -1
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/memory.py +13 -0
- agno/db/singlestore/schemas.py +26 -1
- agno/db/singlestore/singlestore.py +687 -53
- agno/db/singlestore/utils.py +60 -2
- agno/db/sqlite/__init__.py +2 -1
- agno/db/sqlite/async_sqlite.py +2371 -0
- agno/db/sqlite/schemas.py +24 -0
- agno/db/sqlite/sqlite.py +774 -85
- agno/db/sqlite/utils.py +168 -5
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +309 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1361 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +50 -22
- agno/eval/accuracy.py +50 -43
- agno/eval/performance.py +6 -3
- agno/eval/reliability.py +6 -3
- agno/eval/utils.py +33 -16
- agno/exceptions.py +68 -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/integrations/discord/client.py +1 -0
- agno/knowledge/chunking/agentic.py +13 -10
- agno/knowledge/chunking/fixed.py +1 -1
- agno/knowledge/chunking/semantic.py +40 -8
- agno/knowledge/chunking/strategy.py +59 -15
- agno/knowledge/embedder/aws_bedrock.py +9 -4
- agno/knowledge/embedder/azure_openai.py +54 -0
- agno/knowledge/embedder/base.py +2 -0
- agno/knowledge/embedder/cohere.py +184 -5
- agno/knowledge/embedder/fastembed.py +1 -1
- agno/knowledge/embedder/google.py +79 -1
- agno/knowledge/embedder/huggingface.py +9 -4
- agno/knowledge/embedder/jina.py +63 -0
- agno/knowledge/embedder/mistral.py +78 -11
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/ollama.py +13 -0
- agno/knowledge/embedder/openai.py +37 -65
- agno/knowledge/embedder/sentence_transformer.py +8 -4
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +69 -16
- agno/knowledge/knowledge.py +595 -187
- agno/knowledge/reader/base.py +9 -2
- agno/knowledge/reader/csv_reader.py +8 -10
- agno/knowledge/reader/docx_reader.py +5 -6
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/json_reader.py +6 -5
- agno/knowledge/reader/markdown_reader.py +13 -13
- agno/knowledge/reader/pdf_reader.py +43 -68
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +51 -6
- agno/knowledge/reader/s3_reader.py +3 -15
- agno/knowledge/reader/tavily_reader.py +194 -0
- agno/knowledge/reader/text_reader.py +13 -13
- agno/knowledge/reader/web_search_reader.py +2 -43
- agno/knowledge/reader/website_reader.py +43 -25
- agno/knowledge/reranker/__init__.py +3 -0
- agno/knowledge/types.py +9 -0
- agno/knowledge/utils.py +20 -0
- agno/media.py +339 -266
- agno/memory/manager.py +336 -82
- agno/models/aimlapi/aimlapi.py +2 -2
- agno/models/anthropic/claude.py +183 -37
- agno/models/aws/bedrock.py +52 -112
- agno/models/aws/claude.py +33 -1
- agno/models/azure/ai_foundry.py +33 -15
- agno/models/azure/openai_chat.py +25 -8
- agno/models/base.py +1011 -566
- agno/models/cerebras/cerebras.py +19 -13
- agno/models/cerebras/cerebras_openai.py +8 -5
- agno/models/cohere/chat.py +27 -1
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +57 -0
- agno/models/dashscope/dashscope.py +1 -0
- agno/models/deepinfra/deepinfra.py +2 -2
- agno/models/deepseek/deepseek.py +2 -2
- agno/models/fireworks/fireworks.py +2 -2
- agno/models/google/gemini.py +110 -37
- agno/models/groq/groq.py +28 -11
- agno/models/huggingface/huggingface.py +2 -1
- agno/models/internlm/internlm.py +2 -2
- agno/models/langdb/langdb.py +4 -4
- agno/models/litellm/chat.py +18 -1
- agno/models/litellm/litellm_openai.py +2 -2
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/message.py +143 -4
- agno/models/meta/llama.py +27 -10
- agno/models/meta/llama_openai.py +5 -17
- agno/models/nebius/nebius.py +6 -6
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/nvidia.py +2 -2
- agno/models/ollama/chat.py +60 -6
- agno/models/openai/chat.py +102 -43
- agno/models/openai/responses.py +103 -106
- agno/models/openrouter/openrouter.py +41 -3
- agno/models/perplexity/perplexity.py +4 -5
- agno/models/portkey/portkey.py +3 -3
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +52 -0
- agno/models/response.py +81 -5
- agno/models/sambanova/sambanova.py +2 -2
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +25 -0
- agno/models/together/together.py +2 -2
- agno/models/utils.py +254 -8
- agno/models/vercel/v0.py +2 -2
- agno/models/vertexai/__init__.py +0 -0
- agno/models/vertexai/claude.py +96 -0
- agno/models/vllm/vllm.py +1 -0
- agno/models/xai/xai.py +3 -2
- agno/os/app.py +543 -175
- agno/os/auth.py +24 -14
- agno/os/config.py +1 -0
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/a2a/__init__.py +3 -0
- agno/os/interfaces/a2a/a2a.py +42 -0
- agno/os/interfaces/a2a/router.py +250 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/agui.py +23 -7
- agno/os/interfaces/agui/router.py +27 -3
- agno/os/interfaces/agui/utils.py +242 -142
- agno/os/interfaces/base.py +6 -2
- agno/os/interfaces/slack/router.py +81 -23
- agno/os/interfaces/slack/slack.py +29 -14
- agno/os/interfaces/whatsapp/router.py +11 -4
- agno/os/interfaces/whatsapp/whatsapp.py +14 -7
- agno/os/mcp.py +111 -54
- agno/os/middleware/__init__.py +7 -0
- agno/os/middleware/jwt.py +233 -0
- agno/os/router.py +556 -139
- agno/os/routers/evals/evals.py +71 -34
- agno/os/routers/evals/schemas.py +31 -31
- agno/os/routers/evals/utils.py +6 -5
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/knowledge.py +185 -38
- agno/os/routers/knowledge/schemas.py +82 -22
- agno/os/routers/memory/memory.py +158 -53
- agno/os/routers/memory/schemas.py +20 -16
- agno/os/routers/metrics/metrics.py +20 -8
- agno/os/routers/metrics/schemas.py +16 -16
- agno/os/routers/session/session.py +499 -38
- agno/os/schema.py +308 -198
- agno/os/utils.py +401 -41
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +2 -2
- agno/reasoning/deepseek.py +2 -2
- agno/reasoning/default.py +3 -1
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +2 -2
- agno/reasoning/ollama.py +2 -2
- agno/reasoning/openai.py +7 -2
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +266 -112
- agno/run/base.py +53 -24
- agno/run/team.py +252 -111
- agno/run/workflow.py +156 -45
- agno/session/agent.py +105 -89
- agno/session/summary.py +65 -25
- agno/session/team.py +176 -96
- agno/session/workflow.py +406 -40
- agno/team/team.py +3854 -1692
- agno/tools/brightdata.py +3 -3
- agno/tools/cartesia.py +3 -5
- agno/tools/dalle.py +9 -8
- agno/tools/decorator.py +4 -2
- agno/tools/desi_vocal.py +2 -2
- agno/tools/duckduckgo.py +15 -11
- agno/tools/e2b.py +20 -13
- agno/tools/eleven_labs.py +26 -28
- agno/tools/exa.py +21 -16
- agno/tools/fal.py +4 -4
- agno/tools/file.py +153 -23
- agno/tools/file_generation.py +350 -0
- agno/tools/firecrawl.py +4 -4
- agno/tools/function.py +257 -37
- agno/tools/giphy.py +2 -2
- agno/tools/gmail.py +238 -14
- agno/tools/google_drive.py +270 -0
- agno/tools/googlecalendar.py +36 -8
- agno/tools/googlesheets.py +20 -5
- agno/tools/jira.py +20 -0
- agno/tools/knowledge.py +3 -3
- agno/tools/lumalab.py +3 -3
- 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 +11 -17
- agno/tools/memori.py +1 -53
- agno/tools/memory.py +419 -0
- agno/tools/models/azure_openai.py +2 -2
- agno/tools/models/gemini.py +3 -3
- agno/tools/models/groq.py +3 -5
- agno/tools/models/nebius.py +7 -7
- agno/tools/models_labs.py +25 -15
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +4 -9
- agno/tools/opencv.py +3 -3
- agno/tools/parallel.py +314 -0
- agno/tools/replicate.py +7 -7
- agno/tools/scrapegraph.py +58 -31
- agno/tools/searxng.py +2 -2
- agno/tools/serper.py +2 -2
- agno/tools/slack.py +18 -3
- agno/tools/spider.py +2 -2
- agno/tools/tavily.py +146 -0
- agno/tools/whatsapp.py +1 -1
- agno/tools/workflow.py +278 -0
- agno/tools/yfinance.py +12 -11
- agno/utils/agent.py +820 -0
- agno/utils/audio.py +27 -0
- agno/utils/common.py +90 -1
- agno/utils/events.py +222 -7
- agno/utils/gemini.py +181 -23
- agno/utils/hooks.py +57 -0
- agno/utils/http.py +111 -0
- agno/utils/knowledge.py +12 -5
- agno/utils/log.py +1 -0
- agno/utils/mcp.py +95 -5
- agno/utils/media.py +188 -10
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +60 -0
- agno/utils/models/claude.py +40 -11
- agno/utils/models/cohere.py +1 -1
- agno/utils/models/watsonx.py +1 -1
- agno/utils/openai.py +1 -1
- agno/utils/print_response/agent.py +105 -21
- agno/utils/print_response/team.py +103 -38
- agno/utils/print_response/workflow.py +251 -34
- agno/utils/reasoning.py +22 -1
- agno/utils/serialize.py +32 -0
- agno/utils/streamlit.py +16 -10
- agno/utils/string.py +41 -0
- agno/utils/team.py +98 -9
- agno/utils/tools.py +1 -1
- agno/vectordb/base.py +23 -4
- agno/vectordb/cassandra/cassandra.py +65 -9
- agno/vectordb/chroma/chromadb.py +182 -38
- agno/vectordb/clickhouse/clickhousedb.py +64 -11
- agno/vectordb/couchbase/couchbase.py +105 -10
- agno/vectordb/lancedb/lance_db.py +183 -135
- agno/vectordb/langchaindb/langchaindb.py +25 -7
- agno/vectordb/lightrag/lightrag.py +17 -3
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +46 -7
- agno/vectordb/milvus/milvus.py +126 -9
- agno/vectordb/mongodb/__init__.py +7 -1
- agno/vectordb/mongodb/mongodb.py +112 -7
- agno/vectordb/pgvector/pgvector.py +142 -21
- agno/vectordb/pineconedb/pineconedb.py +80 -8
- agno/vectordb/qdrant/qdrant.py +125 -39
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +694 -0
- agno/vectordb/singlestore/singlestore.py +111 -25
- agno/vectordb/surrealdb/surrealdb.py +31 -5
- agno/vectordb/upstashdb/upstashdb.py +76 -8
- agno/vectordb/weaviate/weaviate.py +86 -15
- agno/workflow/__init__.py +2 -0
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +112 -18
- agno/workflow/loop.py +69 -10
- agno/workflow/parallel.py +266 -118
- agno/workflow/router.py +110 -17
- agno/workflow/step.py +645 -136
- agno/workflow/steps.py +65 -6
- agno/workflow/types.py +71 -33
- agno/workflow/workflow.py +2113 -300
- agno-2.3.0.dist-info/METADATA +618 -0
- agno-2.3.0.dist-info/RECORD +577 -0
- agno-2.3.0.dist-info/licenses/LICENSE +201 -0
- agno/knowledge/reader/url_reader.py +0 -128
- agno/tools/googlesearch.py +0 -98
- agno/tools/mcp.py +0 -610
- agno/utils/models/aws_claude.py +0 -170
- agno-2.0.0rc2.dist-info/METADATA +0 -355
- agno-2.0.0rc2.dist-info/RECORD +0 -515
- agno-2.0.0rc2.dist-info/licenses/LICENSE +0 -375
- {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/WHEEL +0 -0
- {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/top_level.txt +0 -0
agno/models/aws/bedrock.py
CHANGED
|
@@ -6,7 +6,7 @@ from typing import Any, AsyncIterator, Dict, Iterator, List, Optional, Tuple, Ty
|
|
|
6
6
|
from pydantic import BaseModel
|
|
7
7
|
|
|
8
8
|
from agno.exceptions import AgnoError, ModelProviderError
|
|
9
|
-
from agno.models.base import
|
|
9
|
+
from agno.models.base import Model
|
|
10
10
|
from agno.models.message import Message
|
|
11
11
|
from agno.models.metrics import Metrics
|
|
12
12
|
from agno.models.response import ModelResponse
|
|
@@ -360,7 +360,7 @@ class AwsBedrock(Model):
|
|
|
360
360
|
formatted_messages, system_message = self._format_messages(messages)
|
|
361
361
|
|
|
362
362
|
tool_config = None
|
|
363
|
-
if tools
|
|
363
|
+
if tools:
|
|
364
364
|
tool_config = {"tools": self._format_tools_for_request(tools)}
|
|
365
365
|
|
|
366
366
|
body = {
|
|
@@ -408,7 +408,7 @@ class AwsBedrock(Model):
|
|
|
408
408
|
formatted_messages, system_message = self._format_messages(messages)
|
|
409
409
|
|
|
410
410
|
tool_config = None
|
|
411
|
-
if tools
|
|
411
|
+
if tools:
|
|
412
412
|
tool_config = {"tools": self._format_tools_for_request(tools)}
|
|
413
413
|
|
|
414
414
|
body = {
|
|
@@ -426,10 +426,14 @@ class AwsBedrock(Model):
|
|
|
426
426
|
|
|
427
427
|
assistant_message.metrics.start_timer()
|
|
428
428
|
|
|
429
|
+
# Track current tool being built across chunks
|
|
430
|
+
current_tool: Dict[str, Any] = {}
|
|
431
|
+
|
|
429
432
|
for chunk in self.get_client().converse_stream(modelId=self.id, messages=formatted_messages, **body)[
|
|
430
433
|
"stream"
|
|
431
434
|
]:
|
|
432
|
-
|
|
435
|
+
model_response, current_tool = self._parse_provider_response_delta(chunk, current_tool)
|
|
436
|
+
yield model_response
|
|
433
437
|
|
|
434
438
|
assistant_message.metrics.stop_timer()
|
|
435
439
|
|
|
@@ -456,7 +460,7 @@ class AwsBedrock(Model):
|
|
|
456
460
|
formatted_messages, system_message = self._format_messages(messages)
|
|
457
461
|
|
|
458
462
|
tool_config = None
|
|
459
|
-
if tools
|
|
463
|
+
if tools:
|
|
460
464
|
tool_config = {"tools": self._format_tools_for_request(tools)}
|
|
461
465
|
|
|
462
466
|
body = {
|
|
@@ -507,7 +511,7 @@ class AwsBedrock(Model):
|
|
|
507
511
|
formatted_messages, system_message = self._format_messages(messages)
|
|
508
512
|
|
|
509
513
|
tool_config = None
|
|
510
|
-
if tools
|
|
514
|
+
if tools:
|
|
511
515
|
tool_config = {"tools": self._format_tools_for_request(tools)}
|
|
512
516
|
|
|
513
517
|
body = {
|
|
@@ -525,10 +529,14 @@ class AwsBedrock(Model):
|
|
|
525
529
|
|
|
526
530
|
assistant_message.metrics.start_timer()
|
|
527
531
|
|
|
532
|
+
# Track current tool being built across chunks
|
|
533
|
+
current_tool: Dict[str, Any] = {}
|
|
534
|
+
|
|
528
535
|
async with self.get_async_client() as client:
|
|
529
536
|
response = await client.converse_stream(modelId=self.id, messages=formatted_messages, **body)
|
|
530
537
|
async for chunk in response["stream"]:
|
|
531
|
-
|
|
538
|
+
model_response, current_tool = self._parse_provider_response_delta(chunk, current_tool)
|
|
539
|
+
yield model_response
|
|
532
540
|
|
|
533
541
|
assistant_message.metrics.stop_timer()
|
|
534
542
|
|
|
@@ -617,122 +625,54 @@ class AwsBedrock(Model):
|
|
|
617
625
|
|
|
618
626
|
return model_response
|
|
619
627
|
|
|
620
|
-
def
|
|
621
|
-
self,
|
|
622
|
-
|
|
623
|
-
assistant_message: Message,
|
|
624
|
-
stream_data: MessageData,
|
|
625
|
-
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
626
|
-
tools: Optional[List[Dict[str, Any]]] = None,
|
|
627
|
-
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
628
|
-
run_response: Optional[RunOutput] = None,
|
|
629
|
-
) -> Iterator[ModelResponse]:
|
|
630
|
-
"""
|
|
631
|
-
Process the synchronous response stream.
|
|
632
|
-
|
|
633
|
-
Args:
|
|
634
|
-
messages (List[Message]): The messages to include in the request.
|
|
635
|
-
assistant_message (Message): The assistant message.
|
|
636
|
-
stream_data (MessageData): The stream data.
|
|
637
|
-
"""
|
|
638
|
-
for response_delta in self.invoke_stream(
|
|
639
|
-
messages=messages,
|
|
640
|
-
assistant_message=assistant_message,
|
|
641
|
-
response_format=response_format,
|
|
642
|
-
tools=tools,
|
|
643
|
-
tool_choice=tool_choice,
|
|
644
|
-
run_response=run_response,
|
|
645
|
-
):
|
|
646
|
-
should_yield = False
|
|
647
|
-
|
|
648
|
-
if response_delta.content:
|
|
649
|
-
stream_data.response_content += response_delta.content
|
|
650
|
-
should_yield = True
|
|
651
|
-
|
|
652
|
-
if response_delta.tool_calls:
|
|
653
|
-
if stream_data.response_tool_calls is None:
|
|
654
|
-
stream_data.response_tool_calls = []
|
|
655
|
-
stream_data.response_tool_calls.extend(response_delta.tool_calls)
|
|
656
|
-
should_yield = True
|
|
657
|
-
|
|
658
|
-
if should_yield:
|
|
659
|
-
yield response_delta
|
|
660
|
-
|
|
661
|
-
async def aprocess_response_stream(
|
|
662
|
-
self,
|
|
663
|
-
messages: List[Message],
|
|
664
|
-
assistant_message: Message,
|
|
665
|
-
stream_data: MessageData,
|
|
666
|
-
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
667
|
-
tools: Optional[List[Dict[str, Any]]] = None,
|
|
668
|
-
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
669
|
-
run_response: Optional[RunOutput] = None,
|
|
670
|
-
) -> AsyncIterator[ModelResponse]:
|
|
671
|
-
"""
|
|
672
|
-
Process the asynchronous response stream.
|
|
673
|
-
|
|
674
|
-
Args:
|
|
675
|
-
messages (List[Message]): The messages to include in the request.
|
|
676
|
-
assistant_message (Message): The assistant message.
|
|
677
|
-
stream_data (MessageData): The stream data.
|
|
678
|
-
"""
|
|
679
|
-
async for response_delta in self.ainvoke_stream(
|
|
680
|
-
messages=messages,
|
|
681
|
-
assistant_message=assistant_message,
|
|
682
|
-
response_format=response_format,
|
|
683
|
-
tools=tools,
|
|
684
|
-
tool_choice=tool_choice,
|
|
685
|
-
run_response=run_response,
|
|
686
|
-
):
|
|
687
|
-
should_yield = False
|
|
688
|
-
|
|
689
|
-
if response_delta.content:
|
|
690
|
-
stream_data.response_content += response_delta.content
|
|
691
|
-
should_yield = True
|
|
692
|
-
|
|
693
|
-
if response_delta.tool_calls:
|
|
694
|
-
if stream_data.response_tool_calls is None:
|
|
695
|
-
stream_data.response_tool_calls = []
|
|
696
|
-
stream_data.response_tool_calls.extend(response_delta.tool_calls)
|
|
697
|
-
should_yield = True
|
|
698
|
-
|
|
699
|
-
if should_yield:
|
|
700
|
-
yield response_delta
|
|
701
|
-
|
|
702
|
-
self._populate_assistant_message(assistant_message=assistant_message, provider_response=response_delta)
|
|
703
|
-
|
|
704
|
-
def _parse_provider_response_delta(self, response_delta: Dict[str, Any]) -> ModelResponse: # type: ignore
|
|
628
|
+
def _parse_provider_response_delta(
|
|
629
|
+
self, response_delta: Dict[str, Any], current_tool: Dict[str, Any]
|
|
630
|
+
) -> Tuple[ModelResponse, Dict[str, Any]]:
|
|
705
631
|
"""Parse the provider response delta for streaming.
|
|
706
632
|
|
|
707
633
|
Args:
|
|
708
634
|
response_delta: The streaming response delta from AWS Bedrock
|
|
635
|
+
current_tool: The current tool being built across chunks
|
|
709
636
|
|
|
710
637
|
Returns:
|
|
711
|
-
ModelResponse: The parsed model response delta
|
|
638
|
+
Tuple[ModelResponse, Dict[str, Any]]: The parsed model response delta and updated current_tool
|
|
712
639
|
"""
|
|
713
640
|
model_response = ModelResponse(role="assistant")
|
|
714
641
|
|
|
715
|
-
# Handle contentBlockDelta - text content
|
|
716
|
-
if "contentBlockDelta" in response_delta:
|
|
717
|
-
delta = response_delta["contentBlockDelta"]["delta"]
|
|
718
|
-
if "text" in delta:
|
|
719
|
-
model_response.content = delta["text"]
|
|
720
|
-
|
|
721
642
|
# Handle contentBlockStart - tool use start
|
|
722
|
-
|
|
643
|
+
if "contentBlockStart" in response_delta:
|
|
723
644
|
start = response_delta["contentBlockStart"]["start"]
|
|
724
645
|
if "toolUse" in start:
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
646
|
+
# Start a new tool
|
|
647
|
+
tool_use_data = start["toolUse"]
|
|
648
|
+
current_tool = {
|
|
649
|
+
"id": tool_use_data.get("toolUseId", ""),
|
|
650
|
+
"type": "function",
|
|
651
|
+
"function": {
|
|
652
|
+
"name": tool_use_data.get("name", ""),
|
|
653
|
+
"arguments": "", # Will be filled in subsequent deltas
|
|
654
|
+
},
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
# Handle contentBlockDelta - text content or tool input
|
|
658
|
+
elif "contentBlockDelta" in response_delta:
|
|
659
|
+
delta = response_delta["contentBlockDelta"]["delta"]
|
|
660
|
+
if "text" in delta:
|
|
661
|
+
model_response.content = delta["text"]
|
|
662
|
+
elif "toolUse" in delta and current_tool:
|
|
663
|
+
# Accumulate tool input
|
|
664
|
+
tool_input = delta["toolUse"].get("input", "")
|
|
665
|
+
if tool_input:
|
|
666
|
+
current_tool["function"]["arguments"] += tool_input
|
|
667
|
+
|
|
668
|
+
# Handle contentBlockStop - tool use complete
|
|
669
|
+
elif "contentBlockStop" in response_delta and current_tool:
|
|
670
|
+
# Tool is complete, add it to model response
|
|
671
|
+
model_response.tool_calls = [current_tool]
|
|
672
|
+
# Track tool_id in extra for format_function_call_results
|
|
673
|
+
model_response.extra = {"tool_ids": [current_tool["id"]]}
|
|
674
|
+
# Reset current_tool for next tool
|
|
675
|
+
current_tool = {}
|
|
736
676
|
|
|
737
677
|
# Handle metadata/usage information
|
|
738
678
|
elif "metadata" in response_delta or "messageStop" in response_delta:
|
|
@@ -740,7 +680,7 @@ class AwsBedrock(Model):
|
|
|
740
680
|
if "usage" in body:
|
|
741
681
|
model_response.response_usage = self._get_metrics(body["usage"])
|
|
742
682
|
|
|
743
|
-
return model_response
|
|
683
|
+
return model_response, current_tool
|
|
744
684
|
|
|
745
685
|
def _get_metrics(self, response_usage: Dict[str, Any]) -> Metrics:
|
|
746
686
|
"""
|
agno/models/aws/claude.py
CHANGED
|
@@ -2,6 +2,7 @@ from dataclasses import dataclass
|
|
|
2
2
|
from os import getenv
|
|
3
3
|
from typing import Any, AsyncIterator, Dict, Iterator, List, Optional, Type, Union
|
|
4
4
|
|
|
5
|
+
import httpx
|
|
5
6
|
from pydantic import BaseModel
|
|
6
7
|
|
|
7
8
|
from agno.exceptions import ModelProviderError, ModelRateLimitError
|
|
@@ -9,8 +10,9 @@ from agno.models.anthropic import Claude as AnthropicClaude
|
|
|
9
10
|
from agno.models.message import Message
|
|
10
11
|
from agno.models.response import ModelResponse
|
|
11
12
|
from agno.run.agent import RunOutput
|
|
13
|
+
from agno.utils.http import get_default_async_client, get_default_sync_client
|
|
12
14
|
from agno.utils.log import log_debug, log_error, log_warning
|
|
13
|
-
from agno.utils.models.
|
|
15
|
+
from agno.utils.models.claude import format_messages
|
|
14
16
|
|
|
15
17
|
try:
|
|
16
18
|
from anthropic import AnthropicBedrock, APIConnectionError, APIStatusError, AsyncAnthropicBedrock, RateLimitError
|
|
@@ -99,9 +101,23 @@ class Claude(AnthropicClaude):
|
|
|
99
101
|
"aws_region": self.aws_region,
|
|
100
102
|
}
|
|
101
103
|
|
|
104
|
+
if self.timeout is not None:
|
|
105
|
+
client_params["timeout"] = self.timeout
|
|
106
|
+
|
|
102
107
|
if self.client_params:
|
|
103
108
|
client_params.update(self.client_params)
|
|
104
109
|
|
|
110
|
+
if self.http_client:
|
|
111
|
+
if isinstance(self.http_client, httpx.Client):
|
|
112
|
+
client_params["http_client"] = self.http_client
|
|
113
|
+
else:
|
|
114
|
+
log_warning("http_client is not an instance of httpx.Client. Using default global httpx.Client.")
|
|
115
|
+
# Use global sync client when user http_client is invalid
|
|
116
|
+
client_params["http_client"] = get_default_sync_client()
|
|
117
|
+
else:
|
|
118
|
+
# Use global sync client when no custom http_client is provided
|
|
119
|
+
client_params["http_client"] = get_default_sync_client()
|
|
120
|
+
|
|
105
121
|
self.client = AnthropicBedrock(
|
|
106
122
|
**client_params, # type: ignore
|
|
107
123
|
)
|
|
@@ -132,9 +148,25 @@ class Claude(AnthropicClaude):
|
|
|
132
148
|
"aws_region": self.aws_region,
|
|
133
149
|
}
|
|
134
150
|
|
|
151
|
+
if self.timeout is not None:
|
|
152
|
+
client_params["timeout"] = self.timeout
|
|
153
|
+
|
|
135
154
|
if self.client_params:
|
|
136
155
|
client_params.update(self.client_params)
|
|
137
156
|
|
|
157
|
+
if self.http_client:
|
|
158
|
+
if isinstance(self.http_client, httpx.AsyncClient):
|
|
159
|
+
client_params["http_client"] = self.http_client
|
|
160
|
+
else:
|
|
161
|
+
log_warning(
|
|
162
|
+
"http_client is not an instance of httpx.AsyncClient. Using default global httpx.AsyncClient."
|
|
163
|
+
)
|
|
164
|
+
# Use global async client when user http_client is invalid
|
|
165
|
+
client_params["http_client"] = get_default_async_client()
|
|
166
|
+
else:
|
|
167
|
+
# Use global async client when no custom http_client is provided
|
|
168
|
+
client_params["http_client"] = get_default_async_client()
|
|
169
|
+
|
|
138
170
|
self.async_client = AsyncAnthropicBedrock(
|
|
139
171
|
**client_params, # type: ignore
|
|
140
172
|
)
|
agno/models/azure/ai_foundry.py
CHANGED
|
@@ -60,6 +60,7 @@ class AzureAIFoundry(Model):
|
|
|
60
60
|
stop: Optional[Union[str, List[str]]] = None
|
|
61
61
|
seed: Optional[int] = None
|
|
62
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
|
|
63
64
|
request_params: Optional[Dict[str, Any]] = None
|
|
64
65
|
# Client parameters
|
|
65
66
|
api_key: Optional[str] = None
|
|
@@ -116,7 +117,7 @@ class AzureAIFoundry(Model):
|
|
|
116
117
|
name=response_format.__name__,
|
|
117
118
|
schema=response_format.model_json_schema(), # type: ignore
|
|
118
119
|
description=response_format.__doc__,
|
|
119
|
-
strict=
|
|
120
|
+
strict=self.strict_output,
|
|
120
121
|
),
|
|
121
122
|
)
|
|
122
123
|
|
|
@@ -160,7 +161,9 @@ class AzureAIFoundry(Model):
|
|
|
160
161
|
Returns:
|
|
161
162
|
ChatCompletionsClient: An instance of the Azure AI client.
|
|
162
163
|
"""
|
|
163
|
-
if
|
|
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"):
|
|
164
167
|
return self.client
|
|
165
168
|
|
|
166
169
|
client_params = self._get_client_params()
|
|
@@ -174,11 +177,28 @@ class AzureAIFoundry(Model):
|
|
|
174
177
|
Returns:
|
|
175
178
|
AsyncChatCompletionsClient: An instance of the asynchronous Azure AI client.
|
|
176
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
|
+
|
|
177
185
|
client_params = self._get_client_params()
|
|
178
186
|
|
|
179
187
|
self.async_client = AsyncChatCompletionsClient(**client_params)
|
|
180
188
|
return self.async_client
|
|
181
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
|
+
|
|
182
202
|
def invoke(
|
|
183
203
|
self,
|
|
184
204
|
messages: List[Message],
|
|
@@ -236,11 +256,10 @@ class AzureAIFoundry(Model):
|
|
|
236
256
|
run_response.metrics.set_time_to_first_token()
|
|
237
257
|
|
|
238
258
|
assistant_message.metrics.start_timer()
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
)
|
|
259
|
+
provider_response = await self.get_async_client().complete(
|
|
260
|
+
messages=[format_message(m) for m in messages],
|
|
261
|
+
**self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
|
|
262
|
+
)
|
|
244
263
|
assistant_message.metrics.stop_timer()
|
|
245
264
|
|
|
246
265
|
model_response = self._parse_provider_response(provider_response, response_format=response_format) # type: ignore
|
|
@@ -316,14 +335,13 @@ class AzureAIFoundry(Model):
|
|
|
316
335
|
|
|
317
336
|
assistant_message.metrics.start_timer()
|
|
318
337
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
yield self._parse_provider_response_delta(chunk)
|
|
338
|
+
async_stream = await self.get_async_client().complete(
|
|
339
|
+
messages=[format_message(m) for m in messages],
|
|
340
|
+
stream=True,
|
|
341
|
+
**self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
|
|
342
|
+
)
|
|
343
|
+
async for chunk in async_stream: # type: ignore
|
|
344
|
+
yield self._parse_provider_response_delta(chunk)
|
|
327
345
|
|
|
328
346
|
assistant_message.metrics.stop_timer()
|
|
329
347
|
|
agno/models/azure/openai_chat.py
CHANGED
|
@@ -5,6 +5,8 @@ from typing import Any, Dict, Optional
|
|
|
5
5
|
import httpx
|
|
6
6
|
|
|
7
7
|
from agno.models.openai.like import OpenAILike
|
|
8
|
+
from agno.utils.http import get_default_async_client, get_default_sync_client
|
|
9
|
+
from agno.utils.log import log_warning
|
|
8
10
|
|
|
9
11
|
try:
|
|
10
12
|
from openai import AsyncAzureOpenAI as AsyncAzureOpenAIClient
|
|
@@ -70,7 +72,6 @@ class AzureOpenAI(OpenAILike):
|
|
|
70
72
|
"base_url": self.base_url,
|
|
71
73
|
"azure_ad_token": self.azure_ad_token,
|
|
72
74
|
"azure_ad_token_provider": self.azure_ad_token_provider,
|
|
73
|
-
"http_client": self.http_client,
|
|
74
75
|
}
|
|
75
76
|
if self.default_headers is not None:
|
|
76
77
|
_client_params["default_headers"] = self.default_headers
|
|
@@ -95,7 +96,18 @@ class AzureOpenAI(OpenAILike):
|
|
|
95
96
|
|
|
96
97
|
_client_params: Dict[str, Any] = self._get_client_params()
|
|
97
98
|
|
|
98
|
-
|
|
99
|
+
if self.http_client:
|
|
100
|
+
if isinstance(self.http_client, httpx.Client):
|
|
101
|
+
_client_params["http_client"] = self.http_client
|
|
102
|
+
else:
|
|
103
|
+
log_warning("http_client is not an instance of httpx.Client. Using default global httpx.Client.")
|
|
104
|
+
# Use global sync client when user http_client is invalid
|
|
105
|
+
_client_params["http_client"] = get_default_sync_client()
|
|
106
|
+
else:
|
|
107
|
+
# Use global sync client when no custom http_client is provided
|
|
108
|
+
_client_params["http_client"] = get_default_sync_client()
|
|
109
|
+
|
|
110
|
+
# Create client
|
|
99
111
|
self.client = AzureOpenAIClient(**_client_params)
|
|
100
112
|
return self.client
|
|
101
113
|
|
|
@@ -106,18 +118,23 @@ class AzureOpenAI(OpenAILike):
|
|
|
106
118
|
Returns:
|
|
107
119
|
AsyncAzureOpenAIClient: An instance of the asynchronous OpenAI client.
|
|
108
120
|
"""
|
|
109
|
-
if self.async_client:
|
|
121
|
+
if self.async_client and not self.async_client.is_closed():
|
|
110
122
|
return self.async_client
|
|
111
123
|
|
|
112
124
|
_client_params: Dict[str, Any] = self._get_client_params()
|
|
113
125
|
|
|
114
126
|
if self.http_client:
|
|
115
|
-
|
|
127
|
+
if isinstance(self.http_client, httpx.AsyncClient):
|
|
128
|
+
_client_params["http_client"] = self.http_client
|
|
129
|
+
else:
|
|
130
|
+
log_warning(
|
|
131
|
+
"http_client is not an instance of httpx.AsyncClient. Using default global httpx.AsyncClient."
|
|
132
|
+
)
|
|
133
|
+
# Use global async client when user http_client is invalid
|
|
134
|
+
_client_params["http_client"] = get_default_async_client()
|
|
116
135
|
else:
|
|
117
|
-
#
|
|
118
|
-
_client_params["http_client"] =
|
|
119
|
-
limits=httpx.Limits(max_connections=1000, max_keepalive_connections=100)
|
|
120
|
-
)
|
|
136
|
+
# Use global async client when no custom http_client is provided
|
|
137
|
+
_client_params["http_client"] = get_default_async_client()
|
|
121
138
|
|
|
122
139
|
self.async_client = AsyncAzureOpenAIClient(**_client_params)
|
|
123
140
|
return self.async_client
|