agno 2.3.22__py3-none-any.whl → 2.3.24__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 (62) hide show
  1. agno/agent/agent.py +28 -1
  2. agno/agent/remote.py +1 -1
  3. agno/db/mongo/mongo.py +9 -1
  4. agno/db/mysql/async_mysql.py +5 -7
  5. agno/db/mysql/mysql.py +5 -7
  6. agno/db/mysql/schemas.py +39 -21
  7. agno/db/postgres/async_postgres.py +10 -2
  8. agno/db/postgres/postgres.py +5 -7
  9. agno/db/postgres/schemas.py +39 -21
  10. agno/db/singlestore/schemas.py +41 -21
  11. agno/db/singlestore/singlestore.py +14 -3
  12. agno/db/sqlite/async_sqlite.py +7 -2
  13. agno/db/sqlite/schemas.py +36 -21
  14. agno/db/sqlite/sqlite.py +3 -7
  15. agno/knowledge/chunking/markdown.py +94 -8
  16. agno/knowledge/chunking/semantic.py +2 -2
  17. agno/knowledge/knowledge.py +215 -207
  18. agno/models/base.py +32 -8
  19. agno/models/google/gemini.py +27 -4
  20. agno/os/routers/agents/router.py +1 -1
  21. agno/os/routers/evals/evals.py +2 -2
  22. agno/os/routers/knowledge/knowledge.py +21 -5
  23. agno/os/routers/knowledge/schemas.py +1 -1
  24. agno/os/routers/memory/memory.py +4 -4
  25. agno/os/routers/session/session.py +2 -2
  26. agno/os/routers/teams/router.py +2 -2
  27. agno/os/routers/traces/traces.py +3 -3
  28. agno/os/routers/workflows/router.py +1 -1
  29. agno/os/schema.py +1 -1
  30. agno/os/utils.py +1 -1
  31. agno/remote/base.py +1 -1
  32. agno/team/remote.py +1 -1
  33. agno/team/team.py +24 -4
  34. agno/tools/brandfetch.py +27 -18
  35. agno/tools/browserbase.py +150 -13
  36. agno/tools/crawl4ai.py +3 -0
  37. agno/tools/file.py +14 -13
  38. agno/tools/function.py +15 -2
  39. agno/tools/mcp/mcp.py +1 -0
  40. agno/tools/mlx_transcribe.py +10 -7
  41. agno/tools/python.py +14 -6
  42. agno/tools/toolkit.py +122 -23
  43. agno/vectordb/cassandra/cassandra.py +1 -1
  44. agno/vectordb/chroma/chromadb.py +1 -1
  45. agno/vectordb/clickhouse/clickhousedb.py +1 -1
  46. agno/vectordb/couchbase/couchbase.py +1 -1
  47. agno/vectordb/milvus/milvus.py +1 -1
  48. agno/vectordb/mongodb/mongodb.py +13 -3
  49. agno/vectordb/pgvector/pgvector.py +1 -1
  50. agno/vectordb/pineconedb/pineconedb.py +2 -2
  51. agno/vectordb/qdrant/qdrant.py +1 -1
  52. agno/vectordb/redis/redisdb.py +2 -2
  53. agno/vectordb/singlestore/singlestore.py +1 -1
  54. agno/vectordb/surrealdb/surrealdb.py +2 -2
  55. agno/vectordb/weaviate/weaviate.py +1 -1
  56. agno/workflow/remote.py +1 -1
  57. agno/workflow/workflow.py +14 -0
  58. {agno-2.3.22.dist-info → agno-2.3.24.dist-info}/METADATA +1 -1
  59. {agno-2.3.22.dist-info → agno-2.3.24.dist-info}/RECORD +62 -62
  60. {agno-2.3.22.dist-info → agno-2.3.24.dist-info}/WHEEL +0 -0
  61. {agno-2.3.22.dist-info → agno-2.3.24.dist-info}/licenses/LICENSE +0 -0
  62. {agno-2.3.22.dist-info → agno-2.3.24.dist-info}/top_level.txt +0 -0
agno/tools/toolkit.py CHANGED
@@ -1,8 +1,10 @@
1
1
  from collections import OrderedDict
2
- from typing import Any, Callable, Dict, List, Optional, Sequence, Union
2
+ from inspect import iscoroutinefunction
3
+ from pathlib import Path
4
+ from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union
3
5
 
4
6
  from agno.tools.function import Function
5
- from agno.utils.log import log_debug, log_warning, logger
7
+ from agno.utils.log import log_debug, log_error, log_warning, logger
6
8
 
7
9
 
8
10
  class Toolkit:
@@ -14,6 +16,7 @@ class Toolkit:
14
16
  self,
15
17
  name: str = "toolkit",
16
18
  tools: Sequence[Union[Callable[..., Any], Function]] = [],
19
+ async_tools: Optional[Sequence[tuple[Callable[..., Any], str]]] = None,
17
20
  instructions: Optional[str] = None,
18
21
  add_instructions: bool = False,
19
22
  include_tools: Optional[list[str]] = None,
@@ -32,6 +35,9 @@ class Toolkit:
32
35
  Args:
33
36
  name: A descriptive name for the toolkit
34
37
  tools: List of tools to include in the toolkit (can be callables or Function objects from @tool decorator)
38
+ async_tools: List of (async_callable, tool_name) tuples for async variants.
39
+ Used when async methods have different names than sync methods.
40
+ Example: [(self.anavigate_to, "navigate_to"), (self.ascreenshot, "screenshot")]
35
41
  instructions: Instructions for the toolkit
36
42
  add_instructions: Whether to add instructions to the toolkit
37
43
  include_tools: List of tool names to include in the toolkit
@@ -47,7 +53,11 @@ class Toolkit:
47
53
  """
48
54
  self.name: str = name
49
55
  self.tools: Sequence[Union[Callable[..., Any], Function]] = tools
56
+ self._async_tools: Sequence[tuple[Callable[..., Any], str]] = async_tools or []
57
+ # Functions dict - used by agent.run() and agent.print_response()
50
58
  self.functions: Dict[str, Function] = OrderedDict()
59
+ # Async functions dict - used by agent.arun() and agent.aprint_response()
60
+ self.async_functions: Dict[str, Function] = OrderedDict()
51
61
  self.instructions: Optional[str] = instructions
52
62
  self.add_instructions: bool = add_instructions
53
63
 
@@ -71,8 +81,11 @@ class Toolkit:
71
81
  self.cache_dir: Optional[str] = cache_dir
72
82
 
73
83
  # Automatically register all methods if auto_register is True
74
- if auto_register and self.tools:
75
- self._register_tools()
84
+ if auto_register:
85
+ if self.tools:
86
+ self._register_tools()
87
+ if self._async_tools:
88
+ self._register_async_tools()
76
89
 
77
90
  def _get_tool_name(self, tool: Union[Callable[..., Any], Function]) -> str:
78
91
  """Get the name of a tool, whether it's a Function or callable."""
@@ -125,14 +138,25 @@ class Toolkit:
125
138
  log_warning(f"Show result tool(s) not present in the toolkit: {', '.join(missing_show_result)}")
126
139
 
127
140
  def _register_tools(self) -> None:
128
- """Register all tools."""
141
+ """Register all sync tools."""
129
142
  for tool in self.tools:
130
143
  self.register(tool)
131
144
 
145
+ def _register_async_tools(self) -> None:
146
+ """Register all async tools with their mapped names.
147
+
148
+ Async detection is automatic via iscoroutinefunction.
149
+ """
150
+ for async_func, tool_name in self._async_tools:
151
+ self.register(async_func, name=tool_name)
152
+
132
153
  def register(self, function: Union[Callable[..., Any], Function], name: Optional[str] = None) -> None:
133
154
  """Register a function with the toolkit.
134
155
 
135
156
  This method supports both regular callables and Function objects (from @tool decorator).
157
+ Automatically detects if the function is async (using iscoroutinefunction) and registers
158
+ it to the appropriate dict (functions for sync, async_functions for async).
159
+
136
160
  When a Function object is passed (e.g., from a @tool decorated method), it will:
137
161
  1. Extract the configuration from the Function object
138
162
  2. Look for a bound method with the same name on `self`
@@ -140,17 +164,18 @@ class Toolkit:
140
164
 
141
165
  Args:
142
166
  function: The callable or Function object to register
143
- name: Optional custom name for the function
144
-
145
- Returns:
146
- The registered function
167
+ name: Optional custom name for the function (useful for aliasing)
147
168
  """
148
169
  try:
149
170
  # Handle Function objects (from @tool decorator)
150
171
  if isinstance(function, Function):
151
- return self._register_decorated_tool(function, name)
172
+ # Auto-detect if this is an async function
173
+ is_async = function.entrypoint is not None and iscoroutinefunction(function.entrypoint)
174
+ return self._register_decorated_tool(function, name, is_async=is_async)
175
+
176
+ # Handle regular callables - auto-detect async
177
+ is_async = iscoroutinefunction(function)
152
178
 
153
- # Handle regular callables
154
179
  tool_name = name or function.__name__
155
180
  if self.include_tools is not None and tool_name not in self.include_tools:
156
181
  return
@@ -168,14 +193,19 @@ class Toolkit:
168
193
  stop_after_tool_call=tool_name in self.stop_after_tool_call_tools,
169
194
  show_result=tool_name in self.show_result_tools or tool_name in self.stop_after_tool_call_tools,
170
195
  )
171
- self.functions[f.name] = f
172
- log_debug(f"Function: {f.name} registered with {self.name}")
196
+
197
+ if is_async:
198
+ self.async_functions[f.name] = f
199
+ log_debug(f"Async function: {f.name} registered with {self.name}")
200
+ else:
201
+ self.functions[f.name] = f
202
+ log_debug(f"Function: {f.name} registered with {self.name}")
173
203
  except Exception as e:
174
204
  func_name = self._get_tool_name(function)
175
205
  logger.warning(f"Failed to create Function for: {func_name}")
176
206
  raise e
177
207
 
178
- def _register_decorated_tool(self, function: Function, name: Optional[str] = None) -> None:
208
+ def _register_decorated_tool(self, function: Function, name: Optional[str] = None, is_async: bool = False) -> None:
179
209
  """Register a Function object from @tool decorator, binding it to self.
180
210
 
181
211
  When @tool decorator is used on a class method, it creates a Function with an unbound
@@ -185,6 +215,7 @@ class Toolkit:
185
215
  Args:
186
216
  function: The Function object from @tool decorator
187
217
  name: Optional custom name override
218
+ is_async: If True, register to async_functions dict instead of functions
188
219
  """
189
220
  import inspect
190
221
 
@@ -207,14 +238,24 @@ class Toolkit:
207
238
 
208
239
  if params and params[0] == "self":
209
240
  # Create a bound method by wrapping the function to include self
210
- def make_bound_method(func, instance):
211
- def bound(*args, **kwargs):
212
- return func(instance, *args, **kwargs)
241
+ if is_async:
213
242
 
214
- # Preserve function metadata for debugging
215
- bound.__name__ = getattr(func, "__name__", tool_name)
216
- bound.__doc__ = getattr(func, "__doc__", None)
217
- return bound
243
+ def make_bound_method(func, instance):
244
+ async def bound(*args, **kwargs):
245
+ return await func(instance, *args, **kwargs)
246
+
247
+ bound.__name__ = getattr(func, "__name__", tool_name)
248
+ bound.__doc__ = getattr(func, "__doc__", None)
249
+ return bound
250
+ else:
251
+
252
+ def make_bound_method(func, instance):
253
+ def bound(*args, **kwargs):
254
+ return func(instance, *args, **kwargs)
255
+
256
+ bound.__name__ = getattr(func, "__name__", tool_name)
257
+ bound.__doc__ = getattr(func, "__doc__", None)
258
+ return bound
218
259
 
219
260
  bound_method = make_bound_method(original_func, self)
220
261
  else:
@@ -251,8 +292,36 @@ class Toolkit:
251
292
  cache_dir=function.cache_dir if function.cache_dir else self.cache_dir,
252
293
  cache_ttl=function.cache_ttl if function.cache_ttl != 3600 else self.cache_ttl,
253
294
  )
254
- self.functions[f.name] = f
255
- log_debug(f"Function: {f.name} registered with {self.name} (from @tool decorator)")
295
+
296
+ if is_async:
297
+ self.async_functions[f.name] = f
298
+ log_debug(f"Async function: {f.name} registered with {self.name} (from @tool decorator)")
299
+ else:
300
+ self.functions[f.name] = f
301
+ log_debug(f"Function: {f.name} registered with {self.name} (from @tool decorator)")
302
+
303
+ def get_functions(self) -> Dict[str, Function]:
304
+ """Get sync functions dict.
305
+
306
+ Returns:
307
+ Dict of function name to Function for sync execution
308
+ """
309
+ return self.functions
310
+
311
+ def get_async_functions(self) -> Dict[str, Function]:
312
+ """Get functions dict optimized for async execution.
313
+
314
+ Returns a merged dict where async_functions take precedence over functions.
315
+ This allows async-optimized implementations to be automatically used in async contexts,
316
+ while falling back to sync implementations for tools without async variants.
317
+
318
+ Returns:
319
+ Dict of function name to Function, with async variants preferred
320
+ """
321
+ # Merge: start with sync functions, override with async variants
322
+ merged = OrderedDict(self.functions)
323
+ merged.update(self.async_functions)
324
+ return merged
256
325
 
257
326
  @property
258
327
  def requires_connect(self) -> bool:
@@ -275,6 +344,36 @@ class Toolkit:
275
344
  """
276
345
  pass
277
346
 
347
+ def _check_path(self, file_name: str, base_dir: Path, restrict_to_base_dir: bool = True) -> Tuple[bool, Path]:
348
+ """Check if the file path is within the base directory.
349
+
350
+ This method validates that a given file path resolves to a location
351
+ within the specified base_dir, preventing directory traversal attacks.
352
+
353
+ Args:
354
+ file_name: The file name or relative path to check.
355
+ base_dir: The base directory to validate against.
356
+ restrict_to_base_dir: If True, reject paths outside base_dir.
357
+
358
+ Returns:
359
+ Tuple of (is_safe, resolved_path). If not safe, returns base_dir as the path.
360
+ """
361
+ file_path = base_dir.joinpath(file_name).resolve()
362
+
363
+ if not restrict_to_base_dir:
364
+ return True, file_path
365
+
366
+ if base_dir == file_path:
367
+ return True, file_path
368
+
369
+ try:
370
+ file_path.relative_to(base_dir)
371
+ except ValueError:
372
+ log_error(f"Path escapes base directory: {file_name}")
373
+ return False, base_dir
374
+
375
+ return True, file_path
376
+
278
377
  def __repr__(self):
279
378
  return f"<{self.__class__.__name__} name={self.name} functions={list(self.functions.keys())}>"
280
379
 
@@ -32,7 +32,7 @@ class Cassandra(VectorDb):
32
32
  from agno.knowledge.embedder.openai import OpenAIEmbedder
33
33
 
34
34
  embedder = OpenAIEmbedder()
35
- log_info("Embedder not provided, using OpenAIEmbedder as default.")
35
+ log_debug("Embedder not provided, using OpenAIEmbedder as default.")
36
36
  # Initialize base class with name and description
37
37
  super().__init__(name=name, description=description)
38
38
 
@@ -117,7 +117,7 @@ class ChromaDb(VectorDb):
117
117
  from agno.knowledge.embedder.openai import OpenAIEmbedder
118
118
 
119
119
  embedder = OpenAIEmbedder()
120
- log_info("Embedder not provided, using OpenAIEmbedder as default.")
120
+ log_debug("Embedder not provided, using OpenAIEmbedder as default.")
121
121
  self.embedder: Embedder = embedder
122
122
  # Distance metric
123
123
  self.distance: Distance = distance
@@ -71,7 +71,7 @@ class Clickhouse(VectorDb):
71
71
  from agno.knowledge.embedder.openai import OpenAIEmbedder
72
72
 
73
73
  _embedder = OpenAIEmbedder()
74
- log_info("Embedder not provided, using OpenAIEmbedder as default.")
74
+ log_debug("Embedder not provided, using OpenAIEmbedder as default.")
75
75
  self.embedder: Embedder = _embedder
76
76
  self.dimensions: Optional[int] = self.embedder.dimensions
77
77
 
@@ -100,7 +100,7 @@ class CouchbaseSearch(VectorDb):
100
100
  from agno.knowledge.embedder.openai import OpenAIEmbedder
101
101
 
102
102
  embedder = OpenAIEmbedder()
103
- log_info("Embedder not provided, using OpenAIEmbedder as default.")
103
+ log_debug("Embedder not provided, using OpenAIEmbedder as default.")
104
104
  self.embedder = embedder
105
105
  self.overwrite = overwrite
106
106
  self.is_global_level_index = is_global_level_index
@@ -89,7 +89,7 @@ class Milvus(VectorDb):
89
89
  from agno.knowledge.embedder.openai import OpenAIEmbedder
90
90
 
91
91
  embedder = OpenAIEmbedder()
92
- log_info("Embedder not provided, using OpenAIEmbedder as default.")
92
+ log_debug("Embedder not provided, using OpenAIEmbedder as default.")
93
93
  self.embedder: Embedder = embedder
94
94
  self.dimensions: Optional[int] = self.embedder.dimensions
95
95
 
@@ -1,5 +1,6 @@
1
1
  import asyncio
2
2
  import time
3
+ from importlib import metadata
3
4
  from typing import Any, Dict, List, Optional, Union
4
5
 
5
6
  from bson import ObjectId
@@ -20,11 +21,14 @@ except ImportError:
20
21
  try:
21
22
  from pymongo import AsyncMongoClient, MongoClient, errors
22
23
  from pymongo.collection import Collection
24
+ from pymongo.driver_info import DriverInfo
23
25
  from pymongo.operations import SearchIndexModel
24
26
 
25
27
  except ImportError:
26
28
  raise ImportError("`pymongo` not installed. Please install using `pip install pymongo`")
27
29
 
30
+ DRIVER_METADATA = DriverInfo(name="Agno", version=metadata.version("agno"))
31
+
28
32
 
29
33
  class MongoDb(VectorDb):
30
34
  """
@@ -110,7 +114,7 @@ class MongoDb(VectorDb):
110
114
  from agno.knowledge.embedder.openai import OpenAIEmbedder
111
115
 
112
116
  embedder = OpenAIEmbedder()
113
- log_info("Embedder not provided, using OpenAIEmbedder as default.")
117
+ log_debug("Embedder not provided, using OpenAIEmbedder as default.")
114
118
  self.embedder = embedder
115
119
 
116
120
  self.distance_metric = distance_metric
@@ -135,6 +139,11 @@ class MongoDb(VectorDb):
135
139
  self._async_db = None
136
140
  self._async_collection: Optional[Collection] = None
137
141
 
142
+ if self._client is not None:
143
+ # append_metadata was added in PyMongo 4.14.0, but is a valid database name on earlier versions
144
+ if callable(self._client.append_metadata):
145
+ self._client.append_metadata(DRIVER_METADATA)
146
+
138
147
  def _get_client(self) -> MongoClient:
139
148
  """Create or retrieve the MongoDB client."""
140
149
  if self._client is None:
@@ -157,7 +166,7 @@ class MongoDb(VectorDb):
157
166
  warnings.filterwarnings(
158
167
  "ignore", category=UserWarning, message=".*connected to a CosmosDB cluster.*"
159
168
  )
160
- self._client = MongoClient(self.connection_string, **cosmos_kwargs) # type: ignore
169
+ self._client = MongoClient(self.connection_string, **cosmos_kwargs, driver=DRIVER_METADATA) # type: ignore
161
170
 
162
171
  self._client.admin.command("ping")
163
172
 
@@ -173,7 +182,7 @@ class MongoDb(VectorDb):
173
182
  else:
174
183
  try:
175
184
  log_debug("Creating MongoDB Client")
176
- self._client = MongoClient(self.connection_string, **self.kwargs)
185
+ self._client = MongoClient(self.connection_string, **self.kwargs, driver=DRIVER_METADATA) # type: ignore
177
186
  # Trigger a connection to verify the client
178
187
  self._client.admin.command("ping")
179
188
  log_info("Connected to MongoDB successfully.")
@@ -195,6 +204,7 @@ class MongoDb(VectorDb):
195
204
  maxPoolSize=self.kwargs.get("maxPoolSize", 100),
196
205
  retryWrites=self.kwargs.get("retryWrites", True),
197
206
  serverSelectionTimeoutMS=5000,
207
+ driver=DRIVER_METADATA,
198
208
  )
199
209
  # Verify connection
200
210
  try:
@@ -122,7 +122,7 @@ class PgVector(VectorDb):
122
122
  from agno.knowledge.embedder.openai import OpenAIEmbedder
123
123
 
124
124
  embedder = OpenAIEmbedder()
125
- log_info("Embedder not provided, using OpenAIEmbedder as default.")
125
+ log_debug("Embedder not provided, using OpenAIEmbedder as default.")
126
126
  self.embedder: Embedder = embedder
127
127
  self.dimensions: Optional[int] = self.embedder.dimensions
128
128
 
@@ -26,7 +26,7 @@ from agno.filters import FilterExpr
26
26
  from agno.knowledge.document import Document
27
27
  from agno.knowledge.embedder import Embedder
28
28
  from agno.knowledge.reranker.base import Reranker
29
- from agno.utils.log import log_debug, log_info, log_warning, logger
29
+ from agno.utils.log import log_debug, log_warning, logger
30
30
  from agno.vectordb.base import VectorDb
31
31
 
32
32
 
@@ -136,7 +136,7 @@ class PineconeDb(VectorDb):
136
136
  from agno.knowledge.embedder.openai import OpenAIEmbedder
137
137
 
138
138
  _embedder = OpenAIEmbedder()
139
- log_info("Embedder not provided, using OpenAIEmbedder as default.")
139
+ log_debug("Embedder not provided, using OpenAIEmbedder as default.")
140
140
  self.embedder: Embedder = _embedder
141
141
  self.reranker: Optional[Reranker] = reranker
142
142
 
@@ -102,7 +102,7 @@ class Qdrant(VectorDb):
102
102
  from agno.knowledge.embedder.openai import OpenAIEmbedder
103
103
 
104
104
  embedder = OpenAIEmbedder()
105
- log_info("Embedder not provided, using OpenAIEmbedder as default.")
105
+ log_debug("Embedder not provided, using OpenAIEmbedder as default.")
106
106
 
107
107
  self.embedder: Embedder = embedder
108
108
  self.dimensions: Optional[int] = self.embedder.dimensions
@@ -16,7 +16,7 @@ from agno.filters import FilterExpr
16
16
  from agno.knowledge.document import Document
17
17
  from agno.knowledge.embedder import Embedder
18
18
  from agno.knowledge.reranker.base import Reranker
19
- from agno.utils.log import log_debug, log_error, log_info, log_warning
19
+ from agno.utils.log import log_debug, log_error, log_warning
20
20
  from agno.utils.string import hash_string_sha256
21
21
  from agno.vectordb.base import VectorDb
22
22
  from agno.vectordb.distance import Distance
@@ -80,7 +80,7 @@ class RedisDB(VectorDb):
80
80
  from agno.knowledge.embedder.openai import OpenAIEmbedder
81
81
 
82
82
  embedder = OpenAIEmbedder()
83
- log_info("Embedder not provided, using OpenAIEmbedder as default.")
83
+ log_debug("Embedder not provided, using OpenAIEmbedder as default.")
84
84
 
85
85
  self.embedder: Embedder = embedder
86
86
  self.dimensions: Optional[int] = self.embedder.dimensions
@@ -56,7 +56,7 @@ class SingleStore(VectorDb):
56
56
  from agno.knowledge.embedder.openai import OpenAIEmbedder
57
57
 
58
58
  embedder = OpenAIEmbedder()
59
- log_info("Embedder not provided, using OpenAIEmbedder as default.")
59
+ log_debug("Embedder not provided, using OpenAIEmbedder as default.")
60
60
  self.embedder: Embedder = embedder
61
61
  self.dimensions: Optional[int] = self.embedder.dimensions
62
62
 
@@ -14,7 +14,7 @@ except ImportError as e:
14
14
  from agno.filters import FilterExpr
15
15
  from agno.knowledge.document import Document
16
16
  from agno.knowledge.embedder import Embedder
17
- from agno.utils.log import log_debug, log_error, log_info, log_warning
17
+ from agno.utils.log import log_debug, log_error, log_warning
18
18
  from agno.vectordb.base import VectorDb
19
19
  from agno.vectordb.distance import Distance
20
20
 
@@ -135,7 +135,7 @@ class SurrealDb(VectorDb):
135
135
  from agno.knowledge.embedder.openai import OpenAIEmbedder
136
136
 
137
137
  embedder = OpenAIEmbedder()
138
- log_info("Embedder not provided, using OpenAIEmbedder as default.")
138
+ log_debug("Embedder not provided, using OpenAIEmbedder as default.")
139
139
  self.embedder: Embedder = embedder
140
140
  self.dimensions = self.embedder.dimensions
141
141
  self.collection = collection
@@ -81,7 +81,7 @@ class Weaviate(VectorDb):
81
81
  from agno.knowledge.embedder.openai import OpenAIEmbedder
82
82
 
83
83
  embedder = OpenAIEmbedder()
84
- log_info("Embedder not provided, using OpenAIEmbedder as default.")
84
+ log_debug("Embedder not provided, using OpenAIEmbedder as default.")
85
85
  self.embedder: Embedder = embedder
86
86
 
87
87
  # Search setup
agno/workflow/remote.py CHANGED
@@ -340,7 +340,7 @@ class RemoteWorkflow(BaseRemote):
340
340
  )
341
341
  return map_task_result_to_workflow_run_output(task_result, workflow_id=self.workflow_id, user_id=user_id)
342
342
 
343
- async def cancel_run(self, run_id: str, auth_token: Optional[str] = None) -> bool:
343
+ async def acancel_run(self, run_id: str, auth_token: Optional[str] = None) -> bool:
344
344
  """Cancel a running workflow execution.
345
345
 
346
346
  Args:
agno/workflow/workflow.py CHANGED
@@ -36,6 +36,9 @@ from agno.models.message import Message
36
36
  from agno.models.metrics import Metrics
37
37
  from agno.run import RunContext, RunStatus
38
38
  from agno.run.agent import RunContentEvent, RunEvent, RunOutput
39
+ from agno.run.cancel import (
40
+ acancel_run as acancel_run_global,
41
+ )
39
42
  from agno.run.cancel import (
40
43
  acleanup_run,
41
44
  araise_if_cancelled,
@@ -3496,6 +3499,17 @@ class Workflow:
3496
3499
  """
3497
3500
  return cancel_run_global(run_id)
3498
3501
 
3502
+ async def acancel_run(self, run_id: str) -> bool:
3503
+ """Cancel a running workflow execution (async version).
3504
+
3505
+ Args:
3506
+ run_id (str): The run_id to cancel.
3507
+
3508
+ Returns:
3509
+ bool: True if the run was found and marked for cancellation, False otherwise.
3510
+ """
3511
+ return await acancel_run_global(run_id)
3512
+
3499
3513
  @overload
3500
3514
  def run(
3501
3515
  self,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agno
3
- Version: 2.3.22
3
+ Version: 2.3.24
4
4
  Summary: Agno: a lightweight library for building Multi-Agent Systems
5
5
  Author-email: Ashpreet Bedi <ashpreet@agno.com>
6
6
  Project-URL: homepage, https://agno.com