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
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
2
|
from os import getenv
|
|
3
|
-
from typing import Optional
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
4
|
|
|
5
|
+
from agno.exceptions import ModelAuthenticationError
|
|
5
6
|
from agno.models.openai.like import OpenAILike
|
|
6
7
|
|
|
7
8
|
|
|
@@ -23,3 +24,19 @@ class LiteLLMOpenAI(OpenAILike):
|
|
|
23
24
|
|
|
24
25
|
api_key: Optional[str] = field(default_factory=lambda: getenv("LITELLM_API_KEY"))
|
|
25
26
|
base_url: str = "http://0.0.0.0:4000"
|
|
27
|
+
|
|
28
|
+
def _get_client_params(self) -> Dict[str, Any]:
|
|
29
|
+
"""
|
|
30
|
+
Returns client parameters for API requests, checking for LITELLM_API_KEY.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Dict[str, Any]: A dictionary of client parameters for API requests.
|
|
34
|
+
"""
|
|
35
|
+
if not self.api_key:
|
|
36
|
+
self.api_key = getenv("LITELLM_API_KEY")
|
|
37
|
+
if not self.api_key:
|
|
38
|
+
raise ModelAuthenticationError(
|
|
39
|
+
message="LITELLM_API_KEY not set. Please set the LITELLM_API_KEY environment variable.",
|
|
40
|
+
model_name=self.name,
|
|
41
|
+
)
|
|
42
|
+
return super()._get_client_params()
|
agno/models/message.py
CHANGED
|
@@ -42,6 +42,9 @@ class Citations(BaseModel):
|
|
|
42
42
|
# Raw citations from the model
|
|
43
43
|
raw: Optional[Any] = None
|
|
44
44
|
|
|
45
|
+
# Search queries used to retrieve the citations
|
|
46
|
+
search_queries: Optional[List[str]] = None
|
|
47
|
+
|
|
45
48
|
# URLs of the citations.
|
|
46
49
|
urls: Optional[List[UrlCitation]] = None
|
|
47
50
|
|
|
@@ -59,6 +62,9 @@ class Message(BaseModel):
|
|
|
59
62
|
role: str
|
|
60
63
|
# The contents of the message.
|
|
61
64
|
content: Optional[Union[List[Any], str]] = None
|
|
65
|
+
# Compressed content of the message
|
|
66
|
+
compressed_content: Optional[str] = None
|
|
67
|
+
|
|
62
68
|
# An optional name for the participant.
|
|
63
69
|
# Provides the model information to differentiate between participants of the same role.
|
|
64
70
|
name: Optional[str] = None
|
|
@@ -109,6 +115,8 @@ class Message(BaseModel):
|
|
|
109
115
|
references: Optional[MessageReferences] = None
|
|
110
116
|
# The Unix timestamp the message was created.
|
|
111
117
|
created_at: int = Field(default_factory=lambda: int(time()))
|
|
118
|
+
# When True, the message will be sent to the Model but not persisted afterwards.
|
|
119
|
+
temporary: bool = False
|
|
112
120
|
|
|
113
121
|
model_config = ConfigDict(extra="allow", populate_by_name=True, arbitrary_types_allowed=True)
|
|
114
122
|
|
|
@@ -123,6 +131,12 @@ class Message(BaseModel):
|
|
|
123
131
|
return json.dumps(self.content)
|
|
124
132
|
return ""
|
|
125
133
|
|
|
134
|
+
def get_content(self, use_compressed_content: bool = False) -> Optional[Union[List[Any], str]]:
|
|
135
|
+
"""Return tool result content to send to API"""
|
|
136
|
+
if use_compressed_content and self.compressed_content is not None:
|
|
137
|
+
return self.compressed_content
|
|
138
|
+
return self.content
|
|
139
|
+
|
|
126
140
|
@classmethod
|
|
127
141
|
def from_dict(cls, data: Dict[str, Any]) -> "Message":
|
|
128
142
|
# Handle image reconstruction properly
|
|
@@ -266,6 +280,7 @@ class Message(BaseModel):
|
|
|
266
280
|
"content": self.content,
|
|
267
281
|
"reasoning_content": self.reasoning_content,
|
|
268
282
|
"from_history": self.from_history,
|
|
283
|
+
"compressed_content": self.compressed_content,
|
|
269
284
|
"stop_after_tool_call": self.stop_after_tool_call,
|
|
270
285
|
"role": self.role,
|
|
271
286
|
"name": self.name,
|
|
@@ -315,13 +330,14 @@ class Message(BaseModel):
|
|
|
315
330
|
"created_at": self.created_at,
|
|
316
331
|
}
|
|
317
332
|
|
|
318
|
-
def log(self, metrics: bool = True, level: Optional[str] = None):
|
|
333
|
+
def log(self, metrics: bool = True, level: Optional[str] = None, use_compressed_content: bool = False):
|
|
319
334
|
"""Log the message to the console
|
|
320
335
|
|
|
321
336
|
Args:
|
|
322
337
|
metrics (bool): Whether to log the metrics.
|
|
323
338
|
level (str): The level to log the message at. One of debug, info, warning, or error.
|
|
324
339
|
Defaults to debug.
|
|
340
|
+
use_compressed_content (bool): Whether to use compressed content.
|
|
325
341
|
"""
|
|
326
342
|
_logger = log_debug
|
|
327
343
|
if level == "info":
|
|
@@ -348,10 +364,13 @@ class Message(BaseModel):
|
|
|
348
364
|
if self.reasoning_content:
|
|
349
365
|
_logger(f"<reasoning>\n{self.reasoning_content}\n</reasoning>")
|
|
350
366
|
if self.content:
|
|
351
|
-
if
|
|
352
|
-
_logger(self.
|
|
353
|
-
|
|
354
|
-
|
|
367
|
+
if use_compressed_content and self.compressed_content:
|
|
368
|
+
_logger("Compressed content:\n" + self.compressed_content)
|
|
369
|
+
else:
|
|
370
|
+
if isinstance(self.content, str) or isinstance(self.content, list):
|
|
371
|
+
_logger(self.content)
|
|
372
|
+
elif isinstance(self.content, dict):
|
|
373
|
+
_logger(json.dumps(self.content, indent=2))
|
|
355
374
|
if self.tool_calls:
|
|
356
375
|
tool_calls_list = ["Tool Calls:"]
|
|
357
376
|
for tool_call in self.tool_calls:
|
agno/models/meta/llama.py
CHANGED
|
@@ -12,6 +12,7 @@ from agno.models.message import Message
|
|
|
12
12
|
from agno.models.metrics import Metrics
|
|
13
13
|
from agno.models.response import ModelResponse
|
|
14
14
|
from agno.run.agent import RunOutput
|
|
15
|
+
from agno.utils.http import get_default_async_client, get_default_sync_client
|
|
15
16
|
from agno.utils.log import log_debug, log_error, log_warning
|
|
16
17
|
from agno.utils.models.llama import format_message
|
|
17
18
|
|
|
@@ -108,7 +109,12 @@ class Llama(Model):
|
|
|
108
109
|
if isinstance(self.http_client, httpx.Client):
|
|
109
110
|
client_params["http_client"] = self.http_client
|
|
110
111
|
else:
|
|
111
|
-
|
|
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()
|
|
112
118
|
self.client = LlamaAPIClient(**client_params)
|
|
113
119
|
return self.client
|
|
114
120
|
|
|
@@ -123,15 +129,20 @@ class Llama(Model):
|
|
|
123
129
|
return self.async_client
|
|
124
130
|
|
|
125
131
|
client_params: Dict[str, Any] = self._get_client_params()
|
|
126
|
-
if self.http_client
|
|
127
|
-
|
|
132
|
+
if self.http_client:
|
|
133
|
+
if isinstance(self.http_client, httpx.AsyncClient):
|
|
134
|
+
client_params["http_client"] = self.http_client
|
|
135
|
+
else:
|
|
136
|
+
log_warning(
|
|
137
|
+
"http_client is not an instance of httpx.AsyncClient. Using default global httpx.AsyncClient."
|
|
138
|
+
)
|
|
139
|
+
# Use global async client when user http_client is invalid
|
|
140
|
+
client_params["http_client"] = get_default_async_client()
|
|
128
141
|
else:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
limits=httpx.Limits(max_connections=1000, max_keepalive_connections=100)
|
|
134
|
-
)
|
|
142
|
+
# Use global async client when no custom http_client is provided
|
|
143
|
+
client_params["http_client"] = get_default_async_client()
|
|
144
|
+
|
|
145
|
+
# Create and cache the client
|
|
135
146
|
self.async_client = AsyncLlamaAPIClient(**client_params)
|
|
136
147
|
return self.async_client
|
|
137
148
|
|
|
@@ -206,6 +217,7 @@ class Llama(Model):
|
|
|
206
217
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
207
218
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
208
219
|
run_response: Optional[RunOutput] = None,
|
|
220
|
+
compress_tool_results: bool = False,
|
|
209
221
|
) -> ModelResponse:
|
|
210
222
|
"""
|
|
211
223
|
Send a chat completion request to the Llama API.
|
|
@@ -214,7 +226,10 @@ class Llama(Model):
|
|
|
214
226
|
|
|
215
227
|
provider_response = self.get_client().chat.completions.create(
|
|
216
228
|
model=self.id,
|
|
217
|
-
messages=[
|
|
229
|
+
messages=[
|
|
230
|
+
format_message(m, tool_calls=bool(tools), compress_tool_results=compress_tool_results) # type: ignore
|
|
231
|
+
for m in messages
|
|
232
|
+
],
|
|
218
233
|
**self.get_request_params(tools=tools, response_format=response_format),
|
|
219
234
|
)
|
|
220
235
|
|
|
@@ -231,6 +246,7 @@ class Llama(Model):
|
|
|
231
246
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
232
247
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
233
248
|
run_response: Optional[RunOutput] = None,
|
|
249
|
+
compress_tool_results: bool = False,
|
|
234
250
|
) -> ModelResponse:
|
|
235
251
|
"""
|
|
236
252
|
Sends an asynchronous chat completion request to the Llama API.
|
|
@@ -242,7 +258,10 @@ class Llama(Model):
|
|
|
242
258
|
|
|
243
259
|
provider_response = await self.get_async_client().chat.completions.create(
|
|
244
260
|
model=self.id,
|
|
245
|
-
messages=[
|
|
261
|
+
messages=[
|
|
262
|
+
format_message(m, tool_calls=bool(tools), compress_tool_results=compress_tool_results) # type: ignore
|
|
263
|
+
for m in messages
|
|
264
|
+
],
|
|
246
265
|
**self.get_request_params(tools=tools, response_format=response_format),
|
|
247
266
|
)
|
|
248
267
|
|
|
@@ -259,6 +278,7 @@ class Llama(Model):
|
|
|
259
278
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
260
279
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
261
280
|
run_response: Optional[RunOutput] = None,
|
|
281
|
+
compress_tool_results: bool = False,
|
|
262
282
|
) -> Iterator[ModelResponse]:
|
|
263
283
|
"""
|
|
264
284
|
Send a streaming chat completion request to the Llama API.
|
|
@@ -271,7 +291,10 @@ class Llama(Model):
|
|
|
271
291
|
|
|
272
292
|
for chunk in self.get_client().chat.completions.create(
|
|
273
293
|
model=self.id,
|
|
274
|
-
messages=[
|
|
294
|
+
messages=[
|
|
295
|
+
format_message(m, tool_calls=bool(tools), compress_tool_results=compress_tool_results) # type: ignore
|
|
296
|
+
for m in messages
|
|
297
|
+
],
|
|
275
298
|
stream=True,
|
|
276
299
|
**self.get_request_params(tools=tools, response_format=response_format),
|
|
277
300
|
):
|
|
@@ -291,6 +314,7 @@ class Llama(Model):
|
|
|
291
314
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
292
315
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
293
316
|
run_response: Optional[RunOutput] = None,
|
|
317
|
+
compress_tool_results: bool = False,
|
|
294
318
|
) -> AsyncIterator[ModelResponse]:
|
|
295
319
|
"""
|
|
296
320
|
Sends an asynchronous streaming chat completion request to the Llama API.
|
|
@@ -303,7 +327,10 @@ class Llama(Model):
|
|
|
303
327
|
try:
|
|
304
328
|
async for chunk in await self.get_async_client().chat.completions.create(
|
|
305
329
|
model=self.id,
|
|
306
|
-
messages=[
|
|
330
|
+
messages=[
|
|
331
|
+
format_message(m, tool_calls=bool(tools), compress_tool_results=compress_tool_results) # type: ignore
|
|
332
|
+
for m in messages
|
|
333
|
+
],
|
|
307
334
|
stream=True,
|
|
308
335
|
**self.get_request_params(tools=tools, response_format=response_format),
|
|
309
336
|
):
|
agno/models/meta/llama_openai.py
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
1
|
+
from dataclasses import dataclass
|
|
2
2
|
from os import getenv
|
|
3
3
|
from typing import Any, Dict, Optional
|
|
4
4
|
|
|
5
|
-
import httpx
|
|
6
|
-
|
|
7
5
|
try:
|
|
8
6
|
from openai import AsyncOpenAI as AsyncOpenAIClient
|
|
9
7
|
except ImportError:
|
|
10
8
|
raise ImportError("`openai` not installed. Please install using `pip install openai`")
|
|
11
9
|
|
|
10
|
+
from agno.exceptions import ModelAuthenticationError
|
|
12
11
|
from agno.models.meta.llama import Message
|
|
13
12
|
from agno.models.openai.like import OpenAILike
|
|
14
13
|
from agno.utils.models.llama import format_message
|
|
@@ -31,7 +30,7 @@ class LlamaOpenAI(OpenAILike):
|
|
|
31
30
|
name: str = "LlamaOpenAI"
|
|
32
31
|
provider: str = "LlamaOpenAI"
|
|
33
32
|
|
|
34
|
-
api_key: Optional[str] =
|
|
33
|
+
api_key: Optional[str] = None
|
|
35
34
|
base_url: Optional[str] = "https://api.llama.com/compat/v1/"
|
|
36
35
|
|
|
37
36
|
# Request parameters
|
|
@@ -48,6 +47,25 @@ class LlamaOpenAI(OpenAILike):
|
|
|
48
47
|
supports_native_structured_outputs: bool = False
|
|
49
48
|
supports_json_schema_outputs: bool = True
|
|
50
49
|
|
|
50
|
+
# Cached async client
|
|
51
|
+
openai_async_client: Optional[AsyncOpenAIClient] = None
|
|
52
|
+
|
|
53
|
+
def _get_client_params(self) -> Dict[str, Any]:
|
|
54
|
+
"""
|
|
55
|
+
Returns client parameters for API requests, checking for LLAMA_API_KEY.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Dict[str, Any]: A dictionary of client parameters for API requests.
|
|
59
|
+
"""
|
|
60
|
+
if not self.api_key:
|
|
61
|
+
self.api_key = getenv("LLAMA_API_KEY")
|
|
62
|
+
if not self.api_key:
|
|
63
|
+
raise ModelAuthenticationError(
|
|
64
|
+
message="LLAMA_API_KEY not set. Please set the LLAMA_API_KEY environment variable.",
|
|
65
|
+
model_name=self.name,
|
|
66
|
+
)
|
|
67
|
+
return super()._get_client_params()
|
|
68
|
+
|
|
51
69
|
def _format_message(self, message: Message) -> Dict[str, Any]:
|
|
52
70
|
"""
|
|
53
71
|
Format a message into the format expected by Llama API.
|
|
@@ -59,20 +77,3 @@ class LlamaOpenAI(OpenAILike):
|
|
|
59
77
|
Dict[str, Any]: The formatted message.
|
|
60
78
|
"""
|
|
61
79
|
return format_message(message, openai_like=True)
|
|
62
|
-
|
|
63
|
-
def get_async_client(self):
|
|
64
|
-
"""Override to provide custom httpx client that properly handles redirects"""
|
|
65
|
-
if self.async_client and not self.async_client.is_closed():
|
|
66
|
-
return self.async_client
|
|
67
|
-
|
|
68
|
-
client_params = self._get_client_params()
|
|
69
|
-
|
|
70
|
-
# Llama gives a 307 redirect error, so we need to set up a custom client to allow redirects
|
|
71
|
-
client_params["http_client"] = httpx.AsyncClient(
|
|
72
|
-
limits=httpx.Limits(max_connections=1000, max_keepalive_connections=100),
|
|
73
|
-
follow_redirects=True,
|
|
74
|
-
timeout=httpx.Timeout(30.0),
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
self.async_client = AsyncOpenAIClient(**client_params)
|
|
78
|
-
return self.async_client
|
agno/models/metrics.py
CHANGED
|
@@ -13,6 +13,10 @@ class Metrics:
|
|
|
13
13
|
output_tokens: int = 0
|
|
14
14
|
total_tokens: int = 0
|
|
15
15
|
|
|
16
|
+
# Cost of the run
|
|
17
|
+
# Currently only supported by some providers
|
|
18
|
+
cost: Optional[float] = None
|
|
19
|
+
|
|
16
20
|
# Audio token usage
|
|
17
21
|
audio_input_tokens: int = 0
|
|
18
22
|
audio_output_tokens: int = 0
|
|
@@ -43,6 +47,7 @@ class Metrics:
|
|
|
43
47
|
metrics_dict = asdict(self)
|
|
44
48
|
# Remove the timer util if present
|
|
45
49
|
metrics_dict.pop("timer", None)
|
|
50
|
+
# Remove any None, 0, or empty dict values
|
|
46
51
|
metrics_dict = {
|
|
47
52
|
k: v
|
|
48
53
|
for k, v in metrics_dict.items()
|
|
@@ -65,6 +70,13 @@ class Metrics:
|
|
|
65
70
|
reasoning_tokens=self.reasoning_tokens + other.reasoning_tokens,
|
|
66
71
|
)
|
|
67
72
|
|
|
73
|
+
if self.cost is not None and other.cost is not None:
|
|
74
|
+
result.cost = self.cost + other.cost
|
|
75
|
+
elif self.cost is not None:
|
|
76
|
+
result.cost = self.cost
|
|
77
|
+
elif other.cost is not None:
|
|
78
|
+
result.cost = other.cost
|
|
79
|
+
|
|
68
80
|
# Handle provider_metrics
|
|
69
81
|
if self.provider_metrics or other.provider_metrics:
|
|
70
82
|
result.provider_metrics = {}
|
agno/models/mistral/mistral.py
CHANGED
|
@@ -174,11 +174,12 @@ class MistralChat(Model):
|
|
|
174
174
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
175
175
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
176
176
|
run_response: Optional[RunOutput] = None,
|
|
177
|
+
compress_tool_results: bool = False,
|
|
177
178
|
) -> ModelResponse:
|
|
178
179
|
"""
|
|
179
180
|
Send a chat completion request to the Mistral model.
|
|
180
181
|
"""
|
|
181
|
-
mistral_messages = format_messages(messages)
|
|
182
|
+
mistral_messages = format_messages(messages, compress_tool_results)
|
|
182
183
|
try:
|
|
183
184
|
response: Union[ChatCompletionResponse, ParsedChatCompletionResponse]
|
|
184
185
|
if (
|
|
@@ -229,11 +230,12 @@ class MistralChat(Model):
|
|
|
229
230
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
230
231
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
231
232
|
run_response: Optional[RunOutput] = None,
|
|
233
|
+
compress_tool_results: bool = False,
|
|
232
234
|
) -> Iterator[ModelResponse]:
|
|
233
235
|
"""
|
|
234
236
|
Stream the response from the Mistral model.
|
|
235
237
|
"""
|
|
236
|
-
mistral_messages = format_messages(messages)
|
|
238
|
+
mistral_messages = format_messages(messages, compress_tool_results)
|
|
237
239
|
|
|
238
240
|
if run_response and run_response.metrics:
|
|
239
241
|
run_response.metrics.set_time_to_first_token()
|
|
@@ -265,11 +267,12 @@ class MistralChat(Model):
|
|
|
265
267
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
266
268
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
267
269
|
run_response: Optional[RunOutput] = None,
|
|
270
|
+
compress_tool_results: bool = False,
|
|
268
271
|
) -> ModelResponse:
|
|
269
272
|
"""
|
|
270
273
|
Send an asynchronous chat completion request to the Mistral API.
|
|
271
274
|
"""
|
|
272
|
-
mistral_messages = format_messages(messages)
|
|
275
|
+
mistral_messages = format_messages(messages, compress_tool_results)
|
|
273
276
|
try:
|
|
274
277
|
response: Union[ChatCompletionResponse, ParsedChatCompletionResponse]
|
|
275
278
|
if (
|
|
@@ -316,11 +319,12 @@ class MistralChat(Model):
|
|
|
316
319
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
317
320
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
318
321
|
run_response: Optional[RunOutput] = None,
|
|
322
|
+
compress_tool_results: bool = False,
|
|
319
323
|
) -> AsyncIterator[ModelResponse]:
|
|
320
324
|
"""
|
|
321
325
|
Stream an asynchronous response from the Mistral API.
|
|
322
326
|
"""
|
|
323
|
-
mistral_messages = format_messages(messages)
|
|
327
|
+
mistral_messages = format_messages(messages, compress_tool_results)
|
|
324
328
|
try:
|
|
325
329
|
if run_response and run_response.metrics:
|
|
326
330
|
run_response.metrics.set_time_to_first_token()
|
agno/models/n1n/n1n.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from os import getenv
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
from agno.exceptions import ModelAuthenticationError
|
|
6
|
+
from agno.models.openai.like import OpenAILike
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class N1N(OpenAILike):
|
|
11
|
+
"""
|
|
12
|
+
A class for interacting with n1n.ai models.
|
|
13
|
+
|
|
14
|
+
Attributes:
|
|
15
|
+
id (str): The model id. Defaults to "gpt-4o".
|
|
16
|
+
name (str): The model name. Defaults to "N1N".
|
|
17
|
+
provider (str): The provider name. Defaults to "N1N".
|
|
18
|
+
api_key (Optional[str]): The API key.
|
|
19
|
+
base_url (str): The base URL. Defaults to "https://api.n1n.ai/v1".
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
id: str = "gpt-4o"
|
|
23
|
+
name: str = "N1N"
|
|
24
|
+
provider: str = "N1N"
|
|
25
|
+
|
|
26
|
+
api_key: Optional[str] = field(default_factory=lambda: getenv("N1N_API_KEY"))
|
|
27
|
+
base_url: str = "https://api.n1n.ai/v1"
|
|
28
|
+
|
|
29
|
+
def _get_client_params(self) -> Dict[str, Any]:
|
|
30
|
+
# Fetch API key from env if not already set
|
|
31
|
+
if not self.api_key:
|
|
32
|
+
self.api_key = getenv("N1N_API_KEY")
|
|
33
|
+
if not self.api_key:
|
|
34
|
+
# Raise error immediately if key is missing
|
|
35
|
+
raise ModelAuthenticationError(
|
|
36
|
+
message="N1N_API_KEY not set. Please set the N1N_API_KEY environment variable.",
|
|
37
|
+
model_name=self.name,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Define base client params
|
|
41
|
+
base_params = {
|
|
42
|
+
"api_key": self.api_key,
|
|
43
|
+
"organization": self.organization,
|
|
44
|
+
"base_url": self.base_url,
|
|
45
|
+
"timeout": self.timeout,
|
|
46
|
+
"max_retries": self.max_retries,
|
|
47
|
+
"default_headers": self.default_headers,
|
|
48
|
+
"default_query": self.default_query,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# Create client_params dict with non-None values
|
|
52
|
+
client_params = {k: v for k, v in base_params.items() if v is not None}
|
|
53
|
+
|
|
54
|
+
# Add additional client params if provided
|
|
55
|
+
if self.client_params:
|
|
56
|
+
client_params.update(self.client_params)
|
|
57
|
+
return client_params
|
agno/models/nebius/nebius.py
CHANGED
|
@@ -2,36 +2,35 @@ from dataclasses import dataclass, field
|
|
|
2
2
|
from os import getenv
|
|
3
3
|
from typing import Any, Dict, Optional
|
|
4
4
|
|
|
5
|
-
from agno.exceptions import
|
|
5
|
+
from agno.exceptions import ModelAuthenticationError
|
|
6
6
|
from agno.models.openai.like import OpenAILike
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
@dataclass
|
|
10
10
|
class Nebius(OpenAILike):
|
|
11
11
|
"""
|
|
12
|
-
A class for interacting with Nebius
|
|
12
|
+
A class for interacting with Nebius Token Factory models.
|
|
13
13
|
|
|
14
14
|
Attributes:
|
|
15
15
|
id (str): The model id. Defaults to "Qwen/Qwen3-235B-A22B"".
|
|
16
16
|
name (str): The model name. Defaults to "Nebius".
|
|
17
17
|
provider (str): The provider name. Defaults to "Nebius".
|
|
18
18
|
api_key (Optional[str]): The API key.
|
|
19
|
-
base_url (str): The base URL. Defaults to "https://api.
|
|
19
|
+
base_url (str): The base URL. Defaults to "https://api.tokenfactory.nebius.com/v1".
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
id: str = "
|
|
22
|
+
id: str = "openai/gpt-oss-20b" # Default model for chat
|
|
23
23
|
name: str = "Nebius"
|
|
24
24
|
provider: str = "Nebius"
|
|
25
25
|
|
|
26
26
|
api_key: Optional[str] = field(default_factory=lambda: getenv("NEBIUS_API_KEY"))
|
|
27
|
-
base_url: str = "https://api.
|
|
27
|
+
base_url: str = "https://api.tokenfactory.nebius.com/v1/"
|
|
28
28
|
|
|
29
29
|
def _get_client_params(self) -> Dict[str, Any]:
|
|
30
30
|
if not self.api_key:
|
|
31
|
-
raise
|
|
31
|
+
raise ModelAuthenticationError(
|
|
32
32
|
message="NEBIUS_API_KEY not set. Please set the NEBIUS_API_KEY environment variable.",
|
|
33
33
|
model_name=self.name,
|
|
34
|
-
model_id=self.id,
|
|
35
34
|
)
|
|
36
35
|
|
|
37
36
|
# Define base client params
|
agno/models/nvidia/nvidia.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
1
|
+
from dataclasses import dataclass
|
|
2
2
|
from os import getenv
|
|
3
|
-
from typing import Optional
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
4
|
|
|
5
|
+
from agno.exceptions import ModelAuthenticationError
|
|
5
6
|
from agno.models.openai.like import OpenAILike
|
|
6
7
|
|
|
7
8
|
|
|
@@ -22,7 +23,23 @@ class Nvidia(OpenAILike):
|
|
|
22
23
|
name: str = "Nvidia"
|
|
23
24
|
provider: str = "Nvidia"
|
|
24
25
|
|
|
25
|
-
api_key: Optional[str] =
|
|
26
|
+
api_key: Optional[str] = None
|
|
26
27
|
base_url: str = "https://integrate.api.nvidia.com/v1"
|
|
27
28
|
|
|
28
29
|
supports_native_structured_outputs: bool = False
|
|
30
|
+
|
|
31
|
+
def _get_client_params(self) -> Dict[str, Any]:
|
|
32
|
+
"""
|
|
33
|
+
Returns client parameters for API requests, checking for NVIDIA_API_KEY.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Dict[str, Any]: A dictionary of client parameters for API requests.
|
|
37
|
+
"""
|
|
38
|
+
if not self.api_key:
|
|
39
|
+
self.api_key = getenv("NVIDIA_API_KEY")
|
|
40
|
+
if not self.api_key:
|
|
41
|
+
raise ModelAuthenticationError(
|
|
42
|
+
message="NVIDIA_API_KEY not set. Please set the NVIDIA_API_KEY environment variable.",
|
|
43
|
+
model_name=self.name,
|
|
44
|
+
)
|
|
45
|
+
return super()._get_client_params()
|
agno/models/ollama/__init__.py
CHANGED
agno/models/ollama/chat.py
CHANGED
|
@@ -147,19 +147,26 @@ class Ollama(Model):
|
|
|
147
147
|
cleaned_dict = {k: v for k, v in model_dict.items() if v is not None}
|
|
148
148
|
return cleaned_dict
|
|
149
149
|
|
|
150
|
-
def _format_message(self, message: Message) -> Dict[str, Any]:
|
|
150
|
+
def _format_message(self, message: Message, compress_tool_results: bool = False) -> Dict[str, Any]:
|
|
151
151
|
"""
|
|
152
152
|
Format a message into the format expected by Ollama.
|
|
153
153
|
|
|
154
154
|
Args:
|
|
155
155
|
message (Message): The message to format.
|
|
156
|
+
compress_tool_results: Whether to compress tool results.
|
|
156
157
|
|
|
157
158
|
Returns:
|
|
158
159
|
Dict[str, Any]: The formatted message.
|
|
159
160
|
"""
|
|
161
|
+
# Use compressed content for tool messages if compression is active
|
|
162
|
+
if message.role == "tool":
|
|
163
|
+
content = message.get_content(use_compressed_content=compress_tool_results)
|
|
164
|
+
else:
|
|
165
|
+
content = message.content
|
|
166
|
+
|
|
160
167
|
_message: Dict[str, Any] = {
|
|
161
168
|
"role": message.role,
|
|
162
|
-
"content":
|
|
169
|
+
"content": content,
|
|
163
170
|
}
|
|
164
171
|
|
|
165
172
|
if message.role == "assistant" and message.tool_calls is not None:
|
|
@@ -228,6 +235,7 @@ class Ollama(Model):
|
|
|
228
235
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
229
236
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
230
237
|
run_response: Optional[RunOutput] = None,
|
|
238
|
+
compress_tool_results: bool = False,
|
|
231
239
|
) -> ModelResponse:
|
|
232
240
|
"""
|
|
233
241
|
Send a chat request to the Ollama API.
|
|
@@ -241,7 +249,7 @@ class Ollama(Model):
|
|
|
241
249
|
|
|
242
250
|
provider_response = self.get_client().chat(
|
|
243
251
|
model=self.id.strip(),
|
|
244
|
-
messages=[self._format_message(m) for m in messages], # type: ignore
|
|
252
|
+
messages=[self._format_message(m, compress_tool_results) for m in messages], # type: ignore
|
|
245
253
|
**request_kwargs,
|
|
246
254
|
) # type: ignore
|
|
247
255
|
|
|
@@ -258,6 +266,7 @@ class Ollama(Model):
|
|
|
258
266
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
259
267
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
260
268
|
run_response: Optional[RunOutput] = None,
|
|
269
|
+
compress_tool_results: bool = False,
|
|
261
270
|
) -> ModelResponse:
|
|
262
271
|
"""
|
|
263
272
|
Sends an asynchronous chat request to the Ollama API.
|
|
@@ -271,7 +280,7 @@ class Ollama(Model):
|
|
|
271
280
|
|
|
272
281
|
provider_response = await self.get_async_client().chat(
|
|
273
282
|
model=self.id.strip(),
|
|
274
|
-
messages=[self._format_message(m) for m in messages], # type: ignore
|
|
283
|
+
messages=[self._format_message(m, compress_tool_results) for m in messages], # type: ignore
|
|
275
284
|
**request_kwargs,
|
|
276
285
|
) # type: ignore
|
|
277
286
|
|
|
@@ -288,6 +297,7 @@ class Ollama(Model):
|
|
|
288
297
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
289
298
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
290
299
|
run_response: Optional[RunOutput] = None,
|
|
300
|
+
compress_tool_results: bool = False,
|
|
291
301
|
) -> Iterator[ModelResponse]:
|
|
292
302
|
"""
|
|
293
303
|
Sends a streaming chat request to the Ollama API.
|
|
@@ -299,7 +309,7 @@ class Ollama(Model):
|
|
|
299
309
|
|
|
300
310
|
for chunk in self.get_client().chat(
|
|
301
311
|
model=self.id,
|
|
302
|
-
messages=[self._format_message(m) for m in messages], # type: ignore
|
|
312
|
+
messages=[self._format_message(m, compress_tool_results) for m in messages], # type: ignore
|
|
303
313
|
stream=True,
|
|
304
314
|
**self.get_request_params(tools=tools),
|
|
305
315
|
):
|
|
@@ -315,6 +325,7 @@ class Ollama(Model):
|
|
|
315
325
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
316
326
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
317
327
|
run_response: Optional[RunOutput] = None,
|
|
328
|
+
compress_tool_results: bool = False,
|
|
318
329
|
) -> AsyncIterator[ModelResponse]:
|
|
319
330
|
"""
|
|
320
331
|
Sends an asynchronous streaming chat completion request to the Ollama API.
|
|
@@ -326,7 +337,7 @@ class Ollama(Model):
|
|
|
326
337
|
|
|
327
338
|
async for chunk in await self.get_async_client().chat(
|
|
328
339
|
model=self.id.strip(),
|
|
329
|
-
messages=[self._format_message(m) for m in messages], # type: ignore
|
|
340
|
+
messages=[self._format_message(m, compress_tool_results) for m in messages], # type: ignore
|
|
330
341
|
stream=True,
|
|
331
342
|
**self.get_request_params(tools=tools),
|
|
332
343
|
):
|