agno 1.7.6__py3-none-any.whl → 1.7.8__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/tools/function.py CHANGED
@@ -1,8 +1,10 @@
1
1
  from dataclasses import dataclass
2
2
  from functools import partial
3
+ from importlib.metadata import version
3
4
  from typing import Any, Callable, Dict, List, Literal, Optional, Type, TypeVar, get_type_hints
4
5
 
5
6
  from docstring_parser import parse
7
+ from packaging.version import Version
6
8
  from pydantic import BaseModel, Field, validate_call
7
9
 
8
10
  from agno.exceptions import AgentRunException
@@ -323,11 +325,21 @@ class Function(BaseModel):
323
325
  @staticmethod
324
326
  def _wrap_callable(func: Callable) -> Callable:
325
327
  """Wrap a callable with Pydantic's validate_call decorator, if relevant"""
326
- from inspect import isasyncgenfunction
328
+ from inspect import isasyncgenfunction, iscoroutinefunction
327
329
 
328
- # Don't wrap async generator with validate_call
330
+ pydantic_version = Version(version("pydantic"))
331
+
332
+ # Don't wrap async generators validate_call
329
333
  if isasyncgenfunction(func):
330
334
  return func
335
+
336
+ # Don't wrap coroutines with validate_call if pydantic version is less than 2.10.0
337
+ if iscoroutinefunction(func) and pydantic_version < Version("2.10.0"):
338
+ log_debug(
339
+ f"Skipping validate_call for {func.__name__} because pydantic version is less than 2.10.0, please consider upgrading to pydantic 2.10.0 or higher"
340
+ )
341
+ return func
342
+
331
343
  # Don't wrap callables that are already wrapped with validate_call
332
344
  elif getattr(func, "_wrapped_for_validation", False):
333
345
  return func
@@ -599,7 +611,7 @@ class FunctionCall(BaseModel):
599
611
 
600
612
  def execute(self) -> FunctionExecutionResult:
601
613
  """Runs the function call."""
602
- from inspect import isgenerator
614
+ from inspect import isgenerator, isgeneratorfunction
603
615
 
604
616
  if self.function.entrypoint is None:
605
617
  return FunctionExecutionResult(status="failure", error="Entrypoint is not set")
@@ -612,7 +624,7 @@ class FunctionCall(BaseModel):
612
624
  entrypoint_args = self._build_entrypoint_args()
613
625
 
614
626
  # Check cache if enabled and not a generator function
615
- if self.function.cache_results and not isgenerator(self.function.entrypoint):
627
+ if self.function.cache_results and not isgeneratorfunction(self.function.entrypoint):
616
628
  cache_key = self.function._get_cache_key(entrypoint_args, self.arguments)
617
629
  cache_file = self.function._get_cache_file_path(cache_key)
618
630
  cached_result = self.function._get_cached_result(cache_file)
@@ -718,7 +730,7 @@ class FunctionCall(BaseModel):
718
730
  Similar to _build_nested_execution_chain but for async execution.
719
731
  """
720
732
  from functools import reduce
721
- from inspect import isasyncgen, isasyncgenfunction, iscoroutinefunction
733
+ from inspect import isasyncgenfunction, iscoroutinefunction
722
734
 
723
735
  async def execute_entrypoint_async(name, func, args):
724
736
  """Execute the entrypoint function asynchronously."""
@@ -727,9 +739,7 @@ class FunctionCall(BaseModel):
727
739
  arguments.update(self.arguments)
728
740
 
729
741
  result = self.function.entrypoint(**arguments) # type: ignore
730
- if iscoroutinefunction(self.function.entrypoint) and not (
731
- isasyncgen(self.function.entrypoint) or isasyncgenfunction(self.function.entrypoint)
732
- ):
742
+ if iscoroutinefunction(self.function.entrypoint) and not isasyncgenfunction(self.function.entrypoint):
733
743
  result = await result
734
744
  return result
735
745
 
@@ -779,7 +789,7 @@ class FunctionCall(BaseModel):
779
789
 
780
790
  async def aexecute(self) -> FunctionExecutionResult:
781
791
  """Runs the function call asynchronously."""
782
- from inspect import isasyncgen, isasyncgenfunction, iscoroutinefunction, isgenerator
792
+ from inspect import isasyncgen, isasyncgenfunction, iscoroutinefunction, isgenerator, isgeneratorfunction
783
793
 
784
794
  if self.function.entrypoint is None:
785
795
  return FunctionExecutionResult(status="failure", error="Entrypoint is not set")
@@ -796,7 +806,7 @@ class FunctionCall(BaseModel):
796
806
 
797
807
  # Check cache if enabled and not a generator function
798
808
  if self.function.cache_results and not (
799
- isasyncgen(self.function.entrypoint) or isgenerator(self.function.entrypoint)
809
+ isasyncgenfunction(self.function.entrypoint) or isgeneratorfunction(self.function.entrypoint)
800
810
  ):
801
811
  cache_key = self.function._get_cache_key(entrypoint_args, self.arguments)
802
812
  cache_file = self.function._get_cache_file_path(cache_key)
@@ -818,7 +828,7 @@ class FunctionCall(BaseModel):
818
828
  else:
819
829
  result = self.function.entrypoint(**entrypoint_args, **self.arguments)
820
830
 
821
- if isasyncgen(self.function.entrypoint) or isasyncgenfunction(self.function.entrypoint):
831
+ if isasyncgenfunction(self.function.entrypoint):
822
832
  self.result = result # Store async generator directly
823
833
  else:
824
834
  self.result = await result