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.
Files changed (383) hide show
  1. agno/agent/__init__.py +6 -0
  2. agno/agent/agent.py +5252 -3145
  3. agno/agent/remote.py +525 -0
  4. agno/api/api.py +2 -0
  5. agno/client/__init__.py +3 -0
  6. agno/client/a2a/__init__.py +10 -0
  7. agno/client/a2a/client.py +554 -0
  8. agno/client/a2a/schemas.py +112 -0
  9. agno/client/a2a/utils.py +369 -0
  10. agno/client/os.py +2669 -0
  11. agno/compression/__init__.py +3 -0
  12. agno/compression/manager.py +247 -0
  13. agno/culture/manager.py +2 -2
  14. agno/db/base.py +927 -6
  15. agno/db/dynamo/dynamo.py +788 -2
  16. agno/db/dynamo/schemas.py +128 -0
  17. agno/db/dynamo/utils.py +26 -3
  18. agno/db/firestore/firestore.py +674 -50
  19. agno/db/firestore/schemas.py +41 -0
  20. agno/db/firestore/utils.py +25 -10
  21. agno/db/gcs_json/gcs_json_db.py +506 -3
  22. agno/db/gcs_json/utils.py +14 -2
  23. agno/db/in_memory/in_memory_db.py +203 -4
  24. agno/db/in_memory/utils.py +14 -2
  25. agno/db/json/json_db.py +498 -2
  26. agno/db/json/utils.py +14 -2
  27. agno/db/migrations/manager.py +199 -0
  28. agno/db/migrations/utils.py +19 -0
  29. agno/db/migrations/v1_to_v2.py +54 -16
  30. agno/db/migrations/versions/__init__.py +0 -0
  31. agno/db/migrations/versions/v2_3_0.py +977 -0
  32. agno/db/mongo/async_mongo.py +1013 -39
  33. agno/db/mongo/mongo.py +684 -4
  34. agno/db/mongo/schemas.py +48 -0
  35. agno/db/mongo/utils.py +17 -0
  36. agno/db/mysql/__init__.py +2 -1
  37. agno/db/mysql/async_mysql.py +2958 -0
  38. agno/db/mysql/mysql.py +722 -53
  39. agno/db/mysql/schemas.py +77 -11
  40. agno/db/mysql/utils.py +151 -8
  41. agno/db/postgres/async_postgres.py +1254 -137
  42. agno/db/postgres/postgres.py +2316 -93
  43. agno/db/postgres/schemas.py +153 -21
  44. agno/db/postgres/utils.py +22 -7
  45. agno/db/redis/redis.py +531 -3
  46. agno/db/redis/schemas.py +36 -0
  47. agno/db/redis/utils.py +31 -15
  48. agno/db/schemas/evals.py +1 -0
  49. agno/db/schemas/memory.py +20 -9
  50. agno/db/singlestore/schemas.py +70 -1
  51. agno/db/singlestore/singlestore.py +737 -74
  52. agno/db/singlestore/utils.py +13 -3
  53. agno/db/sqlite/async_sqlite.py +1069 -89
  54. agno/db/sqlite/schemas.py +133 -1
  55. agno/db/sqlite/sqlite.py +2203 -165
  56. agno/db/sqlite/utils.py +21 -11
  57. agno/db/surrealdb/models.py +25 -0
  58. agno/db/surrealdb/surrealdb.py +603 -1
  59. agno/db/utils.py +60 -0
  60. agno/eval/__init__.py +26 -3
  61. agno/eval/accuracy.py +25 -12
  62. agno/eval/agent_as_judge.py +871 -0
  63. agno/eval/base.py +29 -0
  64. agno/eval/performance.py +10 -4
  65. agno/eval/reliability.py +22 -13
  66. agno/eval/utils.py +2 -1
  67. agno/exceptions.py +42 -0
  68. agno/hooks/__init__.py +3 -0
  69. agno/hooks/decorator.py +164 -0
  70. agno/integrations/discord/client.py +13 -2
  71. agno/knowledge/__init__.py +4 -0
  72. agno/knowledge/chunking/code.py +90 -0
  73. agno/knowledge/chunking/document.py +65 -4
  74. agno/knowledge/chunking/fixed.py +4 -1
  75. agno/knowledge/chunking/markdown.py +102 -11
  76. agno/knowledge/chunking/recursive.py +2 -2
  77. agno/knowledge/chunking/semantic.py +130 -48
  78. agno/knowledge/chunking/strategy.py +18 -0
  79. agno/knowledge/embedder/azure_openai.py +0 -1
  80. agno/knowledge/embedder/google.py +1 -1
  81. agno/knowledge/embedder/mistral.py +1 -1
  82. agno/knowledge/embedder/nebius.py +1 -1
  83. agno/knowledge/embedder/openai.py +16 -12
  84. agno/knowledge/filesystem.py +412 -0
  85. agno/knowledge/knowledge.py +4261 -1199
  86. agno/knowledge/protocol.py +134 -0
  87. agno/knowledge/reader/arxiv_reader.py +3 -2
  88. agno/knowledge/reader/base.py +9 -7
  89. agno/knowledge/reader/csv_reader.py +91 -42
  90. agno/knowledge/reader/docx_reader.py +9 -10
  91. agno/knowledge/reader/excel_reader.py +225 -0
  92. agno/knowledge/reader/field_labeled_csv_reader.py +38 -48
  93. agno/knowledge/reader/firecrawl_reader.py +3 -2
  94. agno/knowledge/reader/json_reader.py +16 -22
  95. agno/knowledge/reader/markdown_reader.py +15 -14
  96. agno/knowledge/reader/pdf_reader.py +33 -28
  97. agno/knowledge/reader/pptx_reader.py +9 -10
  98. agno/knowledge/reader/reader_factory.py +135 -1
  99. agno/knowledge/reader/s3_reader.py +8 -16
  100. agno/knowledge/reader/tavily_reader.py +3 -3
  101. agno/knowledge/reader/text_reader.py +15 -14
  102. agno/knowledge/reader/utils/__init__.py +17 -0
  103. agno/knowledge/reader/utils/spreadsheet.py +114 -0
  104. agno/knowledge/reader/web_search_reader.py +8 -65
  105. agno/knowledge/reader/website_reader.py +16 -13
  106. agno/knowledge/reader/wikipedia_reader.py +36 -3
  107. agno/knowledge/reader/youtube_reader.py +3 -2
  108. agno/knowledge/remote_content/__init__.py +33 -0
  109. agno/knowledge/remote_content/config.py +266 -0
  110. agno/knowledge/remote_content/remote_content.py +105 -17
  111. agno/knowledge/utils.py +76 -22
  112. agno/learn/__init__.py +71 -0
  113. agno/learn/config.py +463 -0
  114. agno/learn/curate.py +185 -0
  115. agno/learn/machine.py +725 -0
  116. agno/learn/schemas.py +1114 -0
  117. agno/learn/stores/__init__.py +38 -0
  118. agno/learn/stores/decision_log.py +1156 -0
  119. agno/learn/stores/entity_memory.py +3275 -0
  120. agno/learn/stores/learned_knowledge.py +1583 -0
  121. agno/learn/stores/protocol.py +117 -0
  122. agno/learn/stores/session_context.py +1217 -0
  123. agno/learn/stores/user_memory.py +1495 -0
  124. agno/learn/stores/user_profile.py +1220 -0
  125. agno/learn/utils.py +209 -0
  126. agno/media.py +22 -6
  127. agno/memory/__init__.py +14 -1
  128. agno/memory/manager.py +223 -8
  129. agno/memory/strategies/__init__.py +15 -0
  130. agno/memory/strategies/base.py +66 -0
  131. agno/memory/strategies/summarize.py +196 -0
  132. agno/memory/strategies/types.py +37 -0
  133. agno/models/aimlapi/aimlapi.py +17 -0
  134. agno/models/anthropic/claude.py +434 -59
  135. agno/models/aws/bedrock.py +121 -20
  136. agno/models/aws/claude.py +131 -274
  137. agno/models/azure/ai_foundry.py +10 -6
  138. agno/models/azure/openai_chat.py +33 -10
  139. agno/models/base.py +1162 -561
  140. agno/models/cerebras/cerebras.py +120 -24
  141. agno/models/cerebras/cerebras_openai.py +21 -2
  142. agno/models/cohere/chat.py +65 -6
  143. agno/models/cometapi/cometapi.py +18 -1
  144. agno/models/dashscope/dashscope.py +2 -3
  145. agno/models/deepinfra/deepinfra.py +18 -1
  146. agno/models/deepseek/deepseek.py +69 -3
  147. agno/models/fireworks/fireworks.py +18 -1
  148. agno/models/google/gemini.py +959 -89
  149. agno/models/google/utils.py +22 -0
  150. agno/models/groq/groq.py +48 -18
  151. agno/models/huggingface/huggingface.py +17 -6
  152. agno/models/ibm/watsonx.py +16 -6
  153. agno/models/internlm/internlm.py +18 -1
  154. agno/models/langdb/langdb.py +13 -1
  155. agno/models/litellm/chat.py +88 -9
  156. agno/models/litellm/litellm_openai.py +18 -1
  157. agno/models/message.py +24 -5
  158. agno/models/meta/llama.py +40 -13
  159. agno/models/meta/llama_openai.py +22 -21
  160. agno/models/metrics.py +12 -0
  161. agno/models/mistral/mistral.py +8 -4
  162. agno/models/n1n/__init__.py +3 -0
  163. agno/models/n1n/n1n.py +57 -0
  164. agno/models/nebius/nebius.py +6 -7
  165. agno/models/nvidia/nvidia.py +20 -3
  166. agno/models/ollama/__init__.py +2 -0
  167. agno/models/ollama/chat.py +17 -6
  168. agno/models/ollama/responses.py +100 -0
  169. agno/models/openai/__init__.py +2 -0
  170. agno/models/openai/chat.py +117 -26
  171. agno/models/openai/open_responses.py +46 -0
  172. agno/models/openai/responses.py +110 -32
  173. agno/models/openrouter/__init__.py +2 -0
  174. agno/models/openrouter/openrouter.py +67 -2
  175. agno/models/openrouter/responses.py +146 -0
  176. agno/models/perplexity/perplexity.py +19 -1
  177. agno/models/portkey/portkey.py +7 -6
  178. agno/models/requesty/requesty.py +19 -2
  179. agno/models/response.py +20 -2
  180. agno/models/sambanova/sambanova.py +20 -3
  181. agno/models/siliconflow/siliconflow.py +19 -2
  182. agno/models/together/together.py +20 -3
  183. agno/models/vercel/v0.py +20 -3
  184. agno/models/vertexai/claude.py +124 -4
  185. agno/models/vllm/vllm.py +19 -14
  186. agno/models/xai/xai.py +19 -2
  187. agno/os/app.py +467 -137
  188. agno/os/auth.py +253 -5
  189. agno/os/config.py +22 -0
  190. agno/os/interfaces/a2a/a2a.py +7 -6
  191. agno/os/interfaces/a2a/router.py +635 -26
  192. agno/os/interfaces/a2a/utils.py +32 -33
  193. agno/os/interfaces/agui/agui.py +5 -3
  194. agno/os/interfaces/agui/router.py +26 -16
  195. agno/os/interfaces/agui/utils.py +97 -57
  196. agno/os/interfaces/base.py +7 -7
  197. agno/os/interfaces/slack/router.py +16 -7
  198. agno/os/interfaces/slack/slack.py +7 -7
  199. agno/os/interfaces/whatsapp/router.py +35 -7
  200. agno/os/interfaces/whatsapp/security.py +3 -1
  201. agno/os/interfaces/whatsapp/whatsapp.py +11 -8
  202. agno/os/managers.py +326 -0
  203. agno/os/mcp.py +652 -79
  204. agno/os/middleware/__init__.py +4 -0
  205. agno/os/middleware/jwt.py +718 -115
  206. agno/os/middleware/trailing_slash.py +27 -0
  207. agno/os/router.py +105 -1558
  208. agno/os/routers/agents/__init__.py +3 -0
  209. agno/os/routers/agents/router.py +655 -0
  210. agno/os/routers/agents/schema.py +288 -0
  211. agno/os/routers/components/__init__.py +3 -0
  212. agno/os/routers/components/components.py +475 -0
  213. agno/os/routers/database.py +155 -0
  214. agno/os/routers/evals/evals.py +111 -18
  215. agno/os/routers/evals/schemas.py +38 -5
  216. agno/os/routers/evals/utils.py +80 -11
  217. agno/os/routers/health.py +3 -3
  218. agno/os/routers/knowledge/knowledge.py +284 -35
  219. agno/os/routers/knowledge/schemas.py +14 -2
  220. agno/os/routers/memory/memory.py +274 -11
  221. agno/os/routers/memory/schemas.py +44 -3
  222. agno/os/routers/metrics/metrics.py +30 -15
  223. agno/os/routers/metrics/schemas.py +10 -6
  224. agno/os/routers/registry/__init__.py +3 -0
  225. agno/os/routers/registry/registry.py +337 -0
  226. agno/os/routers/session/session.py +143 -14
  227. agno/os/routers/teams/__init__.py +3 -0
  228. agno/os/routers/teams/router.py +550 -0
  229. agno/os/routers/teams/schema.py +280 -0
  230. agno/os/routers/traces/__init__.py +3 -0
  231. agno/os/routers/traces/schemas.py +414 -0
  232. agno/os/routers/traces/traces.py +549 -0
  233. agno/os/routers/workflows/__init__.py +3 -0
  234. agno/os/routers/workflows/router.py +757 -0
  235. agno/os/routers/workflows/schema.py +139 -0
  236. agno/os/schema.py +157 -584
  237. agno/os/scopes.py +469 -0
  238. agno/os/settings.py +3 -0
  239. agno/os/utils.py +574 -185
  240. agno/reasoning/anthropic.py +85 -1
  241. agno/reasoning/azure_ai_foundry.py +93 -1
  242. agno/reasoning/deepseek.py +102 -2
  243. agno/reasoning/default.py +6 -7
  244. agno/reasoning/gemini.py +87 -3
  245. agno/reasoning/groq.py +109 -2
  246. agno/reasoning/helpers.py +6 -7
  247. agno/reasoning/manager.py +1238 -0
  248. agno/reasoning/ollama.py +93 -1
  249. agno/reasoning/openai.py +115 -1
  250. agno/reasoning/vertexai.py +85 -1
  251. agno/registry/__init__.py +3 -0
  252. agno/registry/registry.py +68 -0
  253. agno/remote/__init__.py +3 -0
  254. agno/remote/base.py +581 -0
  255. agno/run/__init__.py +2 -4
  256. agno/run/agent.py +134 -19
  257. agno/run/base.py +49 -1
  258. agno/run/cancel.py +65 -52
  259. agno/run/cancellation_management/__init__.py +9 -0
  260. agno/run/cancellation_management/base.py +78 -0
  261. agno/run/cancellation_management/in_memory_cancellation_manager.py +100 -0
  262. agno/run/cancellation_management/redis_cancellation_manager.py +236 -0
  263. agno/run/requirement.py +181 -0
  264. agno/run/team.py +111 -19
  265. agno/run/workflow.py +2 -1
  266. agno/session/agent.py +57 -92
  267. agno/session/summary.py +1 -1
  268. agno/session/team.py +62 -115
  269. agno/session/workflow.py +353 -57
  270. agno/skills/__init__.py +17 -0
  271. agno/skills/agent_skills.py +377 -0
  272. agno/skills/errors.py +32 -0
  273. agno/skills/loaders/__init__.py +4 -0
  274. agno/skills/loaders/base.py +27 -0
  275. agno/skills/loaders/local.py +216 -0
  276. agno/skills/skill.py +65 -0
  277. agno/skills/utils.py +107 -0
  278. agno/skills/validator.py +277 -0
  279. agno/table.py +10 -0
  280. agno/team/__init__.py +5 -1
  281. agno/team/remote.py +447 -0
  282. agno/team/team.py +3769 -2202
  283. agno/tools/brandfetch.py +27 -18
  284. agno/tools/browserbase.py +225 -16
  285. agno/tools/crawl4ai.py +3 -0
  286. agno/tools/duckduckgo.py +25 -71
  287. agno/tools/exa.py +0 -21
  288. agno/tools/file.py +14 -13
  289. agno/tools/file_generation.py +12 -6
  290. agno/tools/firecrawl.py +15 -7
  291. agno/tools/function.py +94 -113
  292. agno/tools/google_bigquery.py +11 -2
  293. agno/tools/google_drive.py +4 -3
  294. agno/tools/knowledge.py +9 -4
  295. agno/tools/mcp/mcp.py +301 -18
  296. agno/tools/mcp/multi_mcp.py +269 -14
  297. agno/tools/mem0.py +11 -10
  298. agno/tools/memory.py +47 -46
  299. agno/tools/mlx_transcribe.py +10 -7
  300. agno/tools/models/nebius.py +5 -5
  301. agno/tools/models_labs.py +20 -10
  302. agno/tools/nano_banana.py +151 -0
  303. agno/tools/parallel.py +0 -7
  304. agno/tools/postgres.py +76 -36
  305. agno/tools/python.py +14 -6
  306. agno/tools/reasoning.py +30 -23
  307. agno/tools/redshift.py +406 -0
  308. agno/tools/shopify.py +1519 -0
  309. agno/tools/spotify.py +919 -0
  310. agno/tools/tavily.py +4 -1
  311. agno/tools/toolkit.py +253 -18
  312. agno/tools/websearch.py +93 -0
  313. agno/tools/website.py +1 -1
  314. agno/tools/wikipedia.py +1 -1
  315. agno/tools/workflow.py +56 -48
  316. agno/tools/yfinance.py +12 -11
  317. agno/tracing/__init__.py +12 -0
  318. agno/tracing/exporter.py +161 -0
  319. agno/tracing/schemas.py +276 -0
  320. agno/tracing/setup.py +112 -0
  321. agno/utils/agent.py +251 -10
  322. agno/utils/cryptography.py +22 -0
  323. agno/utils/dttm.py +33 -0
  324. agno/utils/events.py +264 -7
  325. agno/utils/hooks.py +111 -3
  326. agno/utils/http.py +161 -2
  327. agno/utils/mcp.py +49 -8
  328. agno/utils/media.py +22 -1
  329. agno/utils/models/ai_foundry.py +9 -2
  330. agno/utils/models/claude.py +20 -5
  331. agno/utils/models/cohere.py +9 -2
  332. agno/utils/models/llama.py +9 -2
  333. agno/utils/models/mistral.py +4 -2
  334. agno/utils/os.py +0 -0
  335. agno/utils/print_response/agent.py +99 -16
  336. agno/utils/print_response/team.py +223 -24
  337. agno/utils/print_response/workflow.py +0 -2
  338. agno/utils/prompts.py +8 -6
  339. agno/utils/remote.py +23 -0
  340. agno/utils/response.py +1 -13
  341. agno/utils/string.py +91 -2
  342. agno/utils/team.py +62 -12
  343. agno/utils/tokens.py +657 -0
  344. agno/vectordb/base.py +15 -2
  345. agno/vectordb/cassandra/cassandra.py +1 -1
  346. agno/vectordb/chroma/__init__.py +2 -1
  347. agno/vectordb/chroma/chromadb.py +468 -23
  348. agno/vectordb/clickhouse/clickhousedb.py +1 -1
  349. agno/vectordb/couchbase/couchbase.py +6 -2
  350. agno/vectordb/lancedb/lance_db.py +7 -38
  351. agno/vectordb/lightrag/lightrag.py +7 -6
  352. agno/vectordb/milvus/milvus.py +118 -84
  353. agno/vectordb/mongodb/__init__.py +2 -1
  354. agno/vectordb/mongodb/mongodb.py +14 -31
  355. agno/vectordb/pgvector/pgvector.py +120 -66
  356. agno/vectordb/pineconedb/pineconedb.py +2 -19
  357. agno/vectordb/qdrant/__init__.py +2 -1
  358. agno/vectordb/qdrant/qdrant.py +33 -56
  359. agno/vectordb/redis/__init__.py +2 -1
  360. agno/vectordb/redis/redisdb.py +19 -31
  361. agno/vectordb/singlestore/singlestore.py +17 -9
  362. agno/vectordb/surrealdb/surrealdb.py +2 -38
  363. agno/vectordb/weaviate/__init__.py +2 -1
  364. agno/vectordb/weaviate/weaviate.py +7 -3
  365. agno/workflow/__init__.py +5 -1
  366. agno/workflow/agent.py +2 -2
  367. agno/workflow/condition.py +12 -10
  368. agno/workflow/loop.py +28 -9
  369. agno/workflow/parallel.py +21 -13
  370. agno/workflow/remote.py +362 -0
  371. agno/workflow/router.py +12 -9
  372. agno/workflow/step.py +261 -36
  373. agno/workflow/steps.py +12 -8
  374. agno/workflow/types.py +40 -77
  375. agno/workflow/workflow.py +939 -213
  376. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/METADATA +134 -181
  377. agno-2.4.3.dist-info/RECORD +677 -0
  378. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/WHEEL +1 -1
  379. agno/tools/googlesearch.py +0 -98
  380. agno/tools/memori.py +0 -339
  381. agno-2.2.13.dist-info/RECORD +0 -575
  382. {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/licenses/LICENSE +0 -0
  383. {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 isinstance(self.content, str) or isinstance(self.content, list):
352
- _logger(self.content)
353
- elif isinstance(self.content, dict):
354
- _logger(json.dumps(self.content, indent=2))
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
- log_debug("http_client is not an instance of httpx.Client.")
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 and isinstance(self.http_client, httpx.AsyncClient):
127
- client_params["http_client"] = self.http_client
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
- if self.http_client:
130
- log_debug("The current http_client is not async. A default httpx.AsyncClient will be used instead.")
131
- # Create a new async HTTP client with custom limits
132
- client_params["http_client"] = httpx.AsyncClient(
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=[format_message(m, tool_calls=bool(tools)) for m in messages], # type: ignore
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=[format_message(m, tool_calls=bool(tools)) for m in messages], # type: ignore
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=[format_message(m, tool_calls=bool(tools)) for m in messages], # type: ignore
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=[format_message(m, tool_calls=bool(tools)) for m in messages], # type: ignore
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
  ):
@@ -1,14 +1,13 @@
1
- from dataclasses import dataclass, field
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] = field(default_factory=lambda: getenv("LLAMA_API_KEY"))
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 = {}
@@ -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()
@@ -0,0 +1,3 @@
1
+ from agno.models.n1n.n1n import N1N
2
+
3
+ __all__ = ["N1N"]
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
@@ -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 ModelProviderError
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 AI Studio models.
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.studio.nebius.com/v1".
19
+ base_url (str): The base URL. Defaults to "https://api.tokenfactory.nebius.com/v1".
20
20
  """
21
21
 
22
- id: str = "Qwen/Qwen3-4B-fast" # Default model for chat
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.studio.nebius.com/v1/"
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 ModelProviderError(
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
@@ -1,7 +1,8 @@
1
- from dataclasses import dataclass, field
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] = field(default_factory=lambda: getenv("NVIDIA_API_KEY"))
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()
@@ -1,5 +1,7 @@
1
1
  from agno.models.ollama.chat import Ollama
2
+ from agno.models.ollama.responses import OllamaResponses
2
3
 
3
4
  __all__ = [
4
5
  "Ollama",
6
+ "OllamaResponses",
5
7
  ]
@@ -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": message.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
  ):