agno 2.3.2__py3-none-any.whl → 2.3.4__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 (90) hide show
  1. agno/agent/agent.py +513 -185
  2. agno/compression/__init__.py +3 -0
  3. agno/compression/manager.py +176 -0
  4. agno/db/dynamo/dynamo.py +11 -0
  5. agno/db/firestore/firestore.py +5 -1
  6. agno/db/gcs_json/gcs_json_db.py +5 -2
  7. agno/db/in_memory/in_memory_db.py +5 -2
  8. agno/db/json/json_db.py +5 -1
  9. agno/db/migrations/manager.py +4 -4
  10. agno/db/mongo/async_mongo.py +158 -34
  11. agno/db/mongo/mongo.py +6 -2
  12. agno/db/mysql/mysql.py +48 -54
  13. agno/db/postgres/async_postgres.py +66 -52
  14. agno/db/postgres/postgres.py +42 -50
  15. agno/db/redis/redis.py +5 -0
  16. agno/db/redis/utils.py +5 -5
  17. agno/db/singlestore/singlestore.py +99 -108
  18. agno/db/sqlite/async_sqlite.py +29 -27
  19. agno/db/sqlite/sqlite.py +30 -26
  20. agno/knowledge/reader/pdf_reader.py +2 -2
  21. agno/knowledge/reader/tavily_reader.py +0 -1
  22. agno/memory/__init__.py +14 -1
  23. agno/memory/manager.py +217 -4
  24. agno/memory/strategies/__init__.py +15 -0
  25. agno/memory/strategies/base.py +67 -0
  26. agno/memory/strategies/summarize.py +196 -0
  27. agno/memory/strategies/types.py +37 -0
  28. agno/models/aimlapi/aimlapi.py +18 -0
  29. agno/models/anthropic/claude.py +87 -81
  30. agno/models/aws/bedrock.py +38 -16
  31. agno/models/aws/claude.py +97 -277
  32. agno/models/azure/ai_foundry.py +8 -4
  33. agno/models/base.py +101 -14
  34. agno/models/cerebras/cerebras.py +25 -9
  35. agno/models/cerebras/cerebras_openai.py +22 -2
  36. agno/models/cohere/chat.py +18 -6
  37. agno/models/cometapi/cometapi.py +19 -1
  38. agno/models/deepinfra/deepinfra.py +19 -1
  39. agno/models/fireworks/fireworks.py +19 -1
  40. agno/models/google/gemini.py +583 -21
  41. agno/models/groq/groq.py +23 -6
  42. agno/models/huggingface/huggingface.py +22 -7
  43. agno/models/ibm/watsonx.py +21 -7
  44. agno/models/internlm/internlm.py +19 -1
  45. agno/models/langdb/langdb.py +10 -0
  46. agno/models/litellm/chat.py +17 -7
  47. agno/models/litellm/litellm_openai.py +19 -1
  48. agno/models/message.py +19 -5
  49. agno/models/meta/llama.py +25 -5
  50. agno/models/meta/llama_openai.py +18 -0
  51. agno/models/mistral/mistral.py +13 -5
  52. agno/models/nvidia/nvidia.py +19 -1
  53. agno/models/ollama/chat.py +17 -6
  54. agno/models/openai/chat.py +22 -7
  55. agno/models/openai/responses.py +28 -10
  56. agno/models/openrouter/openrouter.py +20 -0
  57. agno/models/perplexity/perplexity.py +17 -0
  58. agno/models/requesty/requesty.py +18 -0
  59. agno/models/sambanova/sambanova.py +19 -1
  60. agno/models/siliconflow/siliconflow.py +19 -1
  61. agno/models/together/together.py +19 -1
  62. agno/models/vercel/v0.py +19 -1
  63. agno/models/vertexai/claude.py +99 -5
  64. agno/models/xai/xai.py +18 -0
  65. agno/os/interfaces/agui/router.py +1 -0
  66. agno/os/interfaces/agui/utils.py +97 -57
  67. agno/os/router.py +16 -0
  68. agno/os/routers/memory/memory.py +143 -0
  69. agno/os/routers/memory/schemas.py +26 -0
  70. agno/os/schema.py +33 -6
  71. agno/os/utils.py +134 -10
  72. agno/run/base.py +2 -1
  73. agno/run/workflow.py +1 -1
  74. agno/team/team.py +566 -219
  75. agno/tools/mcp/mcp.py +1 -1
  76. agno/utils/agent.py +119 -1
  77. agno/utils/models/ai_foundry.py +9 -2
  78. agno/utils/models/claude.py +12 -5
  79. agno/utils/models/cohere.py +9 -2
  80. agno/utils/models/llama.py +9 -2
  81. agno/utils/models/mistral.py +4 -2
  82. agno/utils/print_response/agent.py +37 -2
  83. agno/utils/print_response/team.py +52 -0
  84. agno/utils/tokens.py +41 -0
  85. agno/workflow/types.py +2 -2
  86. {agno-2.3.2.dist-info → agno-2.3.4.dist-info}/METADATA +45 -40
  87. {agno-2.3.2.dist-info → agno-2.3.4.dist-info}/RECORD +90 -83
  88. {agno-2.3.2.dist-info → agno-2.3.4.dist-info}/WHEEL +0 -0
  89. {agno-2.3.2.dist-info → agno-2.3.4.dist-info}/licenses/LICENSE +0 -0
  90. {agno-2.3.2.dist-info → agno-2.3.4.dist-info}/top_level.txt +0 -0
@@ -7,6 +7,7 @@ try:
7
7
  except ImportError:
8
8
  raise ImportError("`openai` not installed. Please install using `pip install openai`")
9
9
 
10
+ from agno.exceptions import ModelProviderError
10
11
  from agno.models.meta.llama import Message
11
12
  from agno.models.openai.like import OpenAILike
12
13
  from agno.utils.models.llama import format_message
@@ -49,6 +50,23 @@ class LlamaOpenAI(OpenAILike):
49
50
  # Cached async client
50
51
  openai_async_client: Optional[AsyncOpenAIClient] = None
51
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 ModelProviderError(
64
+ message="LLAMA_API_KEY not set. Please set the LLAMA_API_KEY environment variable.",
65
+ model_name=self.name,
66
+ model_id=self.id,
67
+ )
68
+ return super()._get_client_params()
69
+
52
70
  def _format_message(self, message: Message) -> Dict[str, Any]:
53
71
  """
54
72
  Format a message into the format expected by Llama API.
@@ -94,7 +94,11 @@ class MistralChat(Model):
94
94
 
95
95
  self.api_key = self.api_key or getenv("MISTRAL_API_KEY")
96
96
  if not self.api_key:
97
- log_error("MISTRAL_API_KEY not set. Please set the MISTRAL_API_KEY environment variable.")
97
+ raise ModelProviderError(
98
+ message="MISTRAL_API_KEY not set. Please set the MISTRAL_API_KEY environment variable.",
99
+ model_name=self.name,
100
+ model_id=self.id,
101
+ )
98
102
 
99
103
  client_params.update(
100
104
  {
@@ -174,11 +178,12 @@ class MistralChat(Model):
174
178
  tools: Optional[List[Dict[str, Any]]] = None,
175
179
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
176
180
  run_response: Optional[RunOutput] = None,
181
+ compress_tool_results: bool = False,
177
182
  ) -> ModelResponse:
178
183
  """
179
184
  Send a chat completion request to the Mistral model.
180
185
  """
181
- mistral_messages = format_messages(messages)
186
+ mistral_messages = format_messages(messages, compress_tool_results)
182
187
  try:
183
188
  response: Union[ChatCompletionResponse, ParsedChatCompletionResponse]
184
189
  if (
@@ -229,11 +234,12 @@ class MistralChat(Model):
229
234
  tools: Optional[List[Dict[str, Any]]] = None,
230
235
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
231
236
  run_response: Optional[RunOutput] = None,
237
+ compress_tool_results: bool = False,
232
238
  ) -> Iterator[ModelResponse]:
233
239
  """
234
240
  Stream the response from the Mistral model.
235
241
  """
236
- mistral_messages = format_messages(messages)
242
+ mistral_messages = format_messages(messages, compress_tool_results)
237
243
 
238
244
  if run_response and run_response.metrics:
239
245
  run_response.metrics.set_time_to_first_token()
@@ -265,11 +271,12 @@ class MistralChat(Model):
265
271
  tools: Optional[List[Dict[str, Any]]] = None,
266
272
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
267
273
  run_response: Optional[RunOutput] = None,
274
+ compress_tool_results: bool = False,
268
275
  ) -> ModelResponse:
269
276
  """
270
277
  Send an asynchronous chat completion request to the Mistral API.
271
278
  """
272
- mistral_messages = format_messages(messages)
279
+ mistral_messages = format_messages(messages, compress_tool_results)
273
280
  try:
274
281
  response: Union[ChatCompletionResponse, ParsedChatCompletionResponse]
275
282
  if (
@@ -316,11 +323,12 @@ class MistralChat(Model):
316
323
  tools: Optional[List[Dict[str, Any]]] = None,
317
324
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
318
325
  run_response: Optional[RunOutput] = None,
326
+ compress_tool_results: bool = False,
319
327
  ) -> AsyncIterator[ModelResponse]:
320
328
  """
321
329
  Stream an asynchronous response from the Mistral API.
322
330
  """
323
- mistral_messages = format_messages(messages)
331
+ mistral_messages = format_messages(messages, compress_tool_results)
324
332
  try:
325
333
  if run_response and run_response.metrics:
326
334
  run_response.metrics.set_time_to_first_token()
@@ -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 ModelProviderError
5
6
  from agno.models.openai.like import OpenAILike
6
7
 
7
8
 
@@ -26,3 +27,20 @@ class Nvidia(OpenAILike):
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 ModelProviderError(
42
+ message="NVIDIA_API_KEY not set. Please set the NVIDIA_API_KEY environment variable.",
43
+ model_name=self.name,
44
+ model_id=self.id,
45
+ )
46
+ return super()._get_client_params()
@@ -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
  ):
@@ -102,7 +102,11 @@ class OpenAIChat(Model):
102
102
  if not self.api_key:
103
103
  self.api_key = getenv("OPENAI_API_KEY")
104
104
  if not self.api_key:
105
- log_error("OPENAI_API_KEY not set. Please set the OPENAI_API_KEY environment variable.")
105
+ raise ModelProviderError(
106
+ message="OPENAI_API_KEY not set. Please set the OPENAI_API_KEY environment variable.",
107
+ model_name=self.name,
108
+ model_id=self.id,
109
+ )
106
110
 
107
111
  # Define base client params
108
112
  base_params = {
@@ -302,19 +306,22 @@ class OpenAIChat(Model):
302
306
  cleaned_dict = {k: v for k, v in model_dict.items() if v is not None}
303
307
  return cleaned_dict
304
308
 
305
- def _format_message(self, message: Message) -> Dict[str, Any]:
309
+ def _format_message(self, message: Message, compress_tool_results: bool = False) -> Dict[str, Any]:
306
310
  """
307
311
  Format a message into the format expected by OpenAI.
308
312
 
309
313
  Args:
310
314
  message (Message): The message to format.
315
+ compress_tool_results: Whether to compress tool results.
311
316
 
312
317
  Returns:
313
318
  Dict[str, Any]: The formatted message.
314
319
  """
320
+ tool_result = message.get_content(use_compressed_content=compress_tool_results)
321
+
315
322
  message_dict: Dict[str, Any] = {
316
323
  "role": self.role_map[message.role] if self.role_map else self.default_role_map[message.role],
317
- "content": message.content,
324
+ "content": tool_result,
318
325
  "name": message.name,
319
326
  "tool_call_id": message.tool_call_id,
320
327
  "tool_calls": message.tool_calls,
@@ -374,6 +381,7 @@ class OpenAIChat(Model):
374
381
  tools: Optional[List[Dict[str, Any]]] = None,
375
382
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
376
383
  run_response: Optional[Union[RunOutput, TeamRunOutput]] = None,
384
+ compress_tool_results: bool = False,
377
385
  ) -> ModelResponse:
378
386
  """
379
387
  Send a chat completion request to the OpenAI API and parse the response.
@@ -384,6 +392,7 @@ class OpenAIChat(Model):
384
392
  response_format (Optional[Union[Dict, Type[BaseModel]]]): The response format to use.
385
393
  tools (Optional[List[Dict[str, Any]]]): The tools to use.
386
394
  tool_choice (Optional[Union[str, Dict[str, Any]]]): The tool choice to use.
395
+ compress_tool_results: Whether to compress tool results.
387
396
 
388
397
  Returns:
389
398
  ModelResponse: The chat completion response from the API.
@@ -396,7 +405,7 @@ class OpenAIChat(Model):
396
405
 
397
406
  provider_response = self.get_client().chat.completions.create(
398
407
  model=self.id,
399
- messages=[self._format_message(m) for m in messages], # type: ignore
408
+ messages=[self._format_message(m, compress_tool_results) for m in messages], # type: ignore
400
409
  **self.get_request_params(
401
410
  response_format=response_format, tools=tools, tool_choice=tool_choice, run_response=run_response
402
411
  ),
@@ -454,6 +463,7 @@ class OpenAIChat(Model):
454
463
  tools: Optional[List[Dict[str, Any]]] = None,
455
464
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
456
465
  run_response: Optional[Union[RunOutput, TeamRunOutput]] = None,
466
+ compress_tool_results: bool = False,
457
467
  ) -> ModelResponse:
458
468
  """
459
469
  Sends an asynchronous chat completion request to the OpenAI API.
@@ -464,6 +474,7 @@ class OpenAIChat(Model):
464
474
  response_format (Optional[Union[Dict, Type[BaseModel]]]): The response format to use.
465
475
  tools (Optional[List[Dict[str, Any]]]): The tools to use.
466
476
  tool_choice (Optional[Union[str, Dict[str, Any]]]): The tool choice to use.
477
+ compress_tool_results: Whether to compress tool results.
467
478
 
468
479
  Returns:
469
480
  ModelResponse: The chat completion response from the API.
@@ -475,7 +486,7 @@ class OpenAIChat(Model):
475
486
  assistant_message.metrics.start_timer()
476
487
  response = await self.get_async_client().chat.completions.create(
477
488
  model=self.id,
478
- messages=[self._format_message(m) for m in messages], # type: ignore
489
+ messages=[self._format_message(m, compress_tool_results) for m in messages], # type: ignore
479
490
  **self.get_request_params(
480
491
  response_format=response_format, tools=tools, tool_choice=tool_choice, run_response=run_response
481
492
  ),
@@ -533,12 +544,14 @@ class OpenAIChat(Model):
533
544
  tools: Optional[List[Dict[str, Any]]] = None,
534
545
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
535
546
  run_response: Optional[Union[RunOutput, TeamRunOutput]] = None,
547
+ compress_tool_results: bool = False,
536
548
  ) -> Iterator[ModelResponse]:
537
549
  """
538
550
  Send a streaming chat completion request to the OpenAI API.
539
551
 
540
552
  Args:
541
553
  messages (List[Message]): A list of messages to send to the model.
554
+ compress_tool_results: Whether to compress tool results.
542
555
 
543
556
  Returns:
544
557
  Iterator[ModelResponse]: An iterator of model responses.
@@ -552,7 +565,7 @@ class OpenAIChat(Model):
552
565
 
553
566
  for chunk in self.get_client().chat.completions.create(
554
567
  model=self.id,
555
- messages=[self._format_message(m) for m in messages], # type: ignore
568
+ messages=[self._format_message(m, compress_tool_results) for m in messages], # type: ignore
556
569
  stream=True,
557
570
  stream_options={"include_usage": True},
558
571
  **self.get_request_params(
@@ -609,12 +622,14 @@ class OpenAIChat(Model):
609
622
  tools: Optional[List[Dict[str, Any]]] = None,
610
623
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
611
624
  run_response: Optional[Union[RunOutput, TeamRunOutput]] = None,
625
+ compress_tool_results: bool = False,
612
626
  ) -> AsyncIterator[ModelResponse]:
613
627
  """
614
628
  Sends an asynchronous streaming chat completion request to the OpenAI API.
615
629
 
616
630
  Args:
617
631
  messages (List[Message]): A list of messages to send to the model.
632
+ compress_tool_results: Whether to compress tool results.
618
633
 
619
634
  Returns:
620
635
  Any: An asynchronous iterator of model responses.
@@ -628,7 +643,7 @@ class OpenAIChat(Model):
628
643
 
629
644
  async_stream = await self.get_async_client().chat.completions.create(
630
645
  model=self.id,
631
- messages=[self._format_message(m) for m in messages], # type: ignore
646
+ messages=[self._format_message(m, compress_tool_results) for m in messages], # type: ignore
632
647
  stream=True,
633
648
  stream_options={"include_usage": True},
634
649
  **self.get_request_params(
@@ -117,7 +117,11 @@ class OpenAIResponses(Model):
117
117
  if not self.api_key:
118
118
  self.api_key = getenv("OPENAI_API_KEY")
119
119
  if not self.api_key:
120
- log_error("OPENAI_API_KEY not set. Please set the OPENAI_API_KEY environment variable.")
120
+ raise ModelProviderError(
121
+ message="OPENAI_API_KEY not set. Please set the OPENAI_API_KEY environment variable.",
122
+ model_name=self.name,
123
+ model_id=self.id,
124
+ )
121
125
 
122
126
  # Define base client params
123
127
  base_params = {
@@ -395,12 +399,15 @@ class OpenAIResponses(Model):
395
399
 
396
400
  return formatted_tools
397
401
 
398
- def _format_messages(self, messages: List[Message]) -> List[Union[Dict[str, Any], ResponseReasoningItem]]:
402
+ def _format_messages(
403
+ self, messages: List[Message], compress_tool_results: bool = False
404
+ ) -> List[Union[Dict[str, Any], ResponseReasoningItem]]:
399
405
  """
400
406
  Format a message into the format expected by OpenAI.
401
407
 
402
408
  Args:
403
409
  messages (List[Message]): The message to format.
410
+ compress_tool_results: Whether to compress tool results.
404
411
 
405
412
  Returns:
406
413
  Dict[str, Any]: The formatted message.
@@ -445,7 +452,7 @@ class OpenAIResponses(Model):
445
452
  if message.role in ["user", "system"]:
446
453
  message_dict: Dict[str, Any] = {
447
454
  "role": self.role_map[message.role],
448
- "content": message.content,
455
+ "content": message.get_content(use_compressed_content=compress_tool_results),
449
456
  }
450
457
  message_dict = {k: v for k, v in message_dict.items() if v is not None}
451
458
 
@@ -469,7 +476,9 @@ class OpenAIResponses(Model):
469
476
 
470
477
  # Tool call result
471
478
  elif message.role == "tool":
472
- if message.tool_call_id and message.content is not None:
479
+ tool_result = message.get_content(use_compressed_content=compress_tool_results)
480
+
481
+ if message.tool_call_id and tool_result is not None:
473
482
  function_call_id = message.tool_call_id
474
483
  # Normalize: if a fc_* id was provided, translate to its corresponding call_* id
475
484
  if isinstance(function_call_id, str) and function_call_id in fc_id_to_call_id:
@@ -477,7 +486,7 @@ class OpenAIResponses(Model):
477
486
  else:
478
487
  call_id_value = function_call_id
479
488
  formatted_messages.append(
480
- {"type": "function_call_output", "call_id": call_id_value, "output": message.content}
489
+ {"type": "function_call_output", "call_id": call_id_value, "output": tool_result}
481
490
  )
482
491
  # Tool Calls
483
492
  elif message.tool_calls is not None and len(message.tool_calls) > 0:
@@ -519,6 +528,7 @@ class OpenAIResponses(Model):
519
528
  tools: Optional[List[Dict[str, Any]]] = None,
520
529
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
521
530
  run_response: Optional[RunOutput] = None,
531
+ compress_tool_results: bool = False,
522
532
  ) -> ModelResponse:
523
533
  """
524
534
  Send a request to the OpenAI Responses API.
@@ -535,7 +545,7 @@ class OpenAIResponses(Model):
535
545
 
536
546
  provider_response = self.get_client().responses.create(
537
547
  model=self.id,
538
- input=self._format_messages(messages), # type: ignore
548
+ input=self._format_messages(messages, compress_tool_results), # type: ignore
539
549
  **request_params,
540
550
  )
541
551
 
@@ -588,6 +598,7 @@ class OpenAIResponses(Model):
588
598
  tools: Optional[List[Dict[str, Any]]] = None,
589
599
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
590
600
  run_response: Optional[RunOutput] = None,
601
+ compress_tool_results: bool = False,
591
602
  ) -> ModelResponse:
592
603
  """
593
604
  Sends an asynchronous request to the OpenAI Responses API.
@@ -604,7 +615,7 @@ class OpenAIResponses(Model):
604
615
 
605
616
  provider_response = await self.get_async_client().responses.create(
606
617
  model=self.id,
607
- input=self._format_messages(messages), # type: ignore
618
+ input=self._format_messages(messages, compress_tool_results), # type: ignore
608
619
  **request_params,
609
620
  )
610
621
 
@@ -657,6 +668,7 @@ class OpenAIResponses(Model):
657
668
  tools: Optional[List[Dict[str, Any]]] = None,
658
669
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
659
670
  run_response: Optional[RunOutput] = None,
671
+ compress_tool_results: bool = False,
660
672
  ) -> Iterator[ModelResponse]:
661
673
  """
662
674
  Send a streaming request to the OpenAI Responses API.
@@ -674,7 +686,7 @@ class OpenAIResponses(Model):
674
686
 
675
687
  for chunk in self.get_client().responses.create(
676
688
  model=self.id,
677
- input=self._format_messages(messages), # type: ignore
689
+ input=self._format_messages(messages, compress_tool_results), # type: ignore
678
690
  stream=True,
679
691
  **request_params,
680
692
  ):
@@ -730,6 +742,7 @@ class OpenAIResponses(Model):
730
742
  tools: Optional[List[Dict[str, Any]]] = None,
731
743
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
732
744
  run_response: Optional[RunOutput] = None,
745
+ compress_tool_results: bool = False,
733
746
  ) -> AsyncIterator[ModelResponse]:
734
747
  """
735
748
  Sends an asynchronous streaming request to the OpenAI Responses API.
@@ -747,7 +760,7 @@ class OpenAIResponses(Model):
747
760
 
748
761
  async_stream = await self.get_async_client().responses.create(
749
762
  model=self.id,
750
- input=self._format_messages(messages), # type: ignore
763
+ input=self._format_messages(messages, compress_tool_results), # type: ignore
751
764
  stream=True,
752
765
  **request_params,
753
766
  )
@@ -793,7 +806,11 @@ class OpenAIResponses(Model):
793
806
  raise ModelProviderError(message=str(exc), model_name=self.name, model_id=self.id) from exc
794
807
 
795
808
  def format_function_call_results(
796
- self, messages: List[Message], function_call_results: List[Message], tool_call_ids: List[str]
809
+ self,
810
+ messages: List[Message],
811
+ function_call_results: List[Message],
812
+ tool_call_ids: List[str],
813
+ compress_tool_results: bool = False,
797
814
  ) -> None:
798
815
  """
799
816
  Handle the results of function calls.
@@ -802,6 +819,7 @@ class OpenAIResponses(Model):
802
819
  messages (List[Message]): The list of conversation messages.
803
820
  function_call_results (List[Message]): The results of the function calls.
804
821
  tool_ids (List[str]): The tool ids.
822
+ compress_tool_results (bool): Whether to compress tool results.
805
823
  """
806
824
  if len(function_call_results) > 0:
807
825
  for _fc_message_index, _fc_message in enumerate(function_call_results):
@@ -4,6 +4,7 @@ from typing import Any, Dict, List, Optional, Type, Union
4
4
 
5
5
  from pydantic import BaseModel
6
6
 
7
+ from agno.exceptions import ModelProviderError
7
8
  from agno.models.openai.like import OpenAILike
8
9
  from agno.run.agent import RunOutput
9
10
 
@@ -34,6 +35,25 @@ class OpenRouter(OpenAILike):
34
35
  max_tokens: int = 1024
35
36
  models: Optional[List[str]] = None # Dynamic model routing https://openrouter.ai/docs/features/model-routing
36
37
 
38
+ def _get_client_params(self) -> Dict[str, Any]:
39
+ """
40
+ Returns client parameters for API requests, checking for OPENROUTER_API_KEY.
41
+
42
+ Returns:
43
+ Dict[str, Any]: A dictionary of client parameters for API requests.
44
+ """
45
+ # Fetch API key from env if not already set
46
+ if not self.api_key:
47
+ self.api_key = getenv("OPENROUTER_API_KEY")
48
+ if not self.api_key:
49
+ raise ModelProviderError(
50
+ message="OPENROUTER_API_KEY not set. Please set the OPENROUTER_API_KEY environment variable.",
51
+ model_name=self.name,
52
+ model_id=self.id,
53
+ )
54
+
55
+ return super()._get_client_params()
56
+
37
57
  def get_request_params(
38
58
  self,
39
59
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
@@ -50,6 +50,23 @@ class Perplexity(OpenAILike):
50
50
  supports_native_structured_outputs: bool = False
51
51
  supports_json_schema_outputs: bool = True
52
52
 
53
+ def _get_client_params(self) -> Dict[str, Any]:
54
+ """
55
+ Returns client parameters for API requests, checking for PERPLEXITY_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("PERPLEXITY_API_KEY")
62
+ if not self.api_key:
63
+ raise ModelProviderError(
64
+ message="PERPLEXITY_API_KEY not set. Please set the PERPLEXITY_API_KEY environment variable.",
65
+ model_name=self.name,
66
+ model_id=self.id,
67
+ )
68
+ return super()._get_client_params()
69
+
53
70
  def get_request_params(
54
71
  self,
55
72
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
@@ -4,6 +4,7 @@ from typing import Any, Dict, List, Optional, Type, Union
4
4
 
5
5
  from pydantic import BaseModel
6
6
 
7
+ from agno.exceptions import ModelProviderError
7
8
  from agno.models.openai.like import OpenAILike
8
9
  from agno.run.agent import RunOutput
9
10
  from agno.run.team import TeamRunOutput
@@ -30,6 +31,23 @@ class Requesty(OpenAILike):
30
31
  base_url: str = "https://router.requesty.ai/v1"
31
32
  max_tokens: int = 1024
32
33
 
34
+ def _get_client_params(self) -> Dict[str, Any]:
35
+ """
36
+ Returns client parameters for API requests, checking for REQUESTY_API_KEY.
37
+
38
+ Returns:
39
+ Dict[str, Any]: A dictionary of client parameters for API requests.
40
+ """
41
+ if not self.api_key:
42
+ self.api_key = getenv("REQUESTY_API_KEY")
43
+ if not self.api_key:
44
+ raise ModelProviderError(
45
+ message="REQUESTY_API_KEY not set. Please set the REQUESTY_API_KEY environment variable.",
46
+ model_name=self.name,
47
+ model_id=self.id,
48
+ )
49
+ return super()._get_client_params()
50
+
33
51
  def get_request_params(
34
52
  self,
35
53
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
@@ -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 ModelProviderError
5
6
  from agno.models.openai.like import OpenAILike
6
7
 
7
8
 
@@ -26,3 +27,20 @@ class Sambanova(OpenAILike):
26
27
  base_url: str = "https://api.sambanova.ai/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 SAMBANOVA_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("SAMBANOVA_API_KEY")
40
+ if not self.api_key:
41
+ raise ModelProviderError(
42
+ message="SAMBANOVA_API_KEY not set. Please set the SAMBANOVA_API_KEY environment variable.",
43
+ model_name=self.name,
44
+ model_id=self.id,
45
+ )
46
+ return super()._get_client_params()
@@ -1,7 +1,8 @@
1
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 ModelProviderError
5
6
  from agno.models.openai.like import OpenAILike
6
7
 
7
8
 
@@ -23,3 +24,20 @@ class Siliconflow(OpenAILike):
23
24
  provider: str = "Siliconflow"
24
25
  api_key: Optional[str] = getenv("SILICONFLOW_API_KEY")
25
26
  base_url: str = "https://api.siliconflow.com/v1"
27
+
28
+ def _get_client_params(self) -> Dict[str, Any]:
29
+ """
30
+ Returns client parameters for API requests, checking for SILICONFLOW_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("SILICONFLOW_API_KEY")
37
+ if not self.api_key:
38
+ raise ModelProviderError(
39
+ message="SILICONFLOW_API_KEY not set. Please set the SILICONFLOW_API_KEY environment variable.",
40
+ model_name=self.name,
41
+ model_id=self.id,
42
+ )
43
+ return super()._get_client_params()