agno 2.0.0rc2__py3-none-any.whl → 2.3.0__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 (331) hide show
  1. agno/agent/agent.py +6009 -2874
  2. agno/api/api.py +2 -0
  3. agno/api/os.py +1 -1
  4. agno/culture/__init__.py +3 -0
  5. agno/culture/manager.py +956 -0
  6. agno/db/async_postgres/__init__.py +3 -0
  7. agno/db/base.py +385 -6
  8. agno/db/dynamo/dynamo.py +388 -81
  9. agno/db/dynamo/schemas.py +47 -10
  10. agno/db/dynamo/utils.py +63 -4
  11. agno/db/firestore/firestore.py +435 -64
  12. agno/db/firestore/schemas.py +11 -0
  13. agno/db/firestore/utils.py +102 -4
  14. agno/db/gcs_json/gcs_json_db.py +384 -42
  15. agno/db/gcs_json/utils.py +60 -26
  16. agno/db/in_memory/in_memory_db.py +351 -66
  17. agno/db/in_memory/utils.py +60 -2
  18. agno/db/json/json_db.py +339 -48
  19. agno/db/json/utils.py +60 -26
  20. agno/db/migrations/manager.py +199 -0
  21. agno/db/migrations/v1_to_v2.py +510 -37
  22. agno/db/migrations/versions/__init__.py +0 -0
  23. agno/db/migrations/versions/v2_3_0.py +938 -0
  24. agno/db/mongo/__init__.py +15 -1
  25. agno/db/mongo/async_mongo.py +2036 -0
  26. agno/db/mongo/mongo.py +653 -76
  27. agno/db/mongo/schemas.py +13 -0
  28. agno/db/mongo/utils.py +80 -8
  29. agno/db/mysql/mysql.py +687 -25
  30. agno/db/mysql/schemas.py +61 -37
  31. agno/db/mysql/utils.py +60 -2
  32. agno/db/postgres/__init__.py +2 -1
  33. agno/db/postgres/async_postgres.py +2001 -0
  34. agno/db/postgres/postgres.py +676 -57
  35. agno/db/postgres/schemas.py +43 -18
  36. agno/db/postgres/utils.py +164 -2
  37. agno/db/redis/redis.py +344 -38
  38. agno/db/redis/schemas.py +18 -0
  39. agno/db/redis/utils.py +60 -2
  40. agno/db/schemas/__init__.py +2 -1
  41. agno/db/schemas/culture.py +120 -0
  42. agno/db/schemas/memory.py +13 -0
  43. agno/db/singlestore/schemas.py +26 -1
  44. agno/db/singlestore/singlestore.py +687 -53
  45. agno/db/singlestore/utils.py +60 -2
  46. agno/db/sqlite/__init__.py +2 -1
  47. agno/db/sqlite/async_sqlite.py +2371 -0
  48. agno/db/sqlite/schemas.py +24 -0
  49. agno/db/sqlite/sqlite.py +774 -85
  50. agno/db/sqlite/utils.py +168 -5
  51. agno/db/surrealdb/__init__.py +3 -0
  52. agno/db/surrealdb/metrics.py +292 -0
  53. agno/db/surrealdb/models.py +309 -0
  54. agno/db/surrealdb/queries.py +71 -0
  55. agno/db/surrealdb/surrealdb.py +1361 -0
  56. agno/db/surrealdb/utils.py +147 -0
  57. agno/db/utils.py +50 -22
  58. agno/eval/accuracy.py +50 -43
  59. agno/eval/performance.py +6 -3
  60. agno/eval/reliability.py +6 -3
  61. agno/eval/utils.py +33 -16
  62. agno/exceptions.py +68 -1
  63. agno/filters.py +354 -0
  64. agno/guardrails/__init__.py +6 -0
  65. agno/guardrails/base.py +19 -0
  66. agno/guardrails/openai.py +144 -0
  67. agno/guardrails/pii.py +94 -0
  68. agno/guardrails/prompt_injection.py +52 -0
  69. agno/integrations/discord/client.py +1 -0
  70. agno/knowledge/chunking/agentic.py +13 -10
  71. agno/knowledge/chunking/fixed.py +1 -1
  72. agno/knowledge/chunking/semantic.py +40 -8
  73. agno/knowledge/chunking/strategy.py +59 -15
  74. agno/knowledge/embedder/aws_bedrock.py +9 -4
  75. agno/knowledge/embedder/azure_openai.py +54 -0
  76. agno/knowledge/embedder/base.py +2 -0
  77. agno/knowledge/embedder/cohere.py +184 -5
  78. agno/knowledge/embedder/fastembed.py +1 -1
  79. agno/knowledge/embedder/google.py +79 -1
  80. agno/knowledge/embedder/huggingface.py +9 -4
  81. agno/knowledge/embedder/jina.py +63 -0
  82. agno/knowledge/embedder/mistral.py +78 -11
  83. agno/knowledge/embedder/nebius.py +1 -1
  84. agno/knowledge/embedder/ollama.py +13 -0
  85. agno/knowledge/embedder/openai.py +37 -65
  86. agno/knowledge/embedder/sentence_transformer.py +8 -4
  87. agno/knowledge/embedder/vllm.py +262 -0
  88. agno/knowledge/embedder/voyageai.py +69 -16
  89. agno/knowledge/knowledge.py +595 -187
  90. agno/knowledge/reader/base.py +9 -2
  91. agno/knowledge/reader/csv_reader.py +8 -10
  92. agno/knowledge/reader/docx_reader.py +5 -6
  93. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  94. agno/knowledge/reader/json_reader.py +6 -5
  95. agno/knowledge/reader/markdown_reader.py +13 -13
  96. agno/knowledge/reader/pdf_reader.py +43 -68
  97. agno/knowledge/reader/pptx_reader.py +101 -0
  98. agno/knowledge/reader/reader_factory.py +51 -6
  99. agno/knowledge/reader/s3_reader.py +3 -15
  100. agno/knowledge/reader/tavily_reader.py +194 -0
  101. agno/knowledge/reader/text_reader.py +13 -13
  102. agno/knowledge/reader/web_search_reader.py +2 -43
  103. agno/knowledge/reader/website_reader.py +43 -25
  104. agno/knowledge/reranker/__init__.py +3 -0
  105. agno/knowledge/types.py +9 -0
  106. agno/knowledge/utils.py +20 -0
  107. agno/media.py +339 -266
  108. agno/memory/manager.py +336 -82
  109. agno/models/aimlapi/aimlapi.py +2 -2
  110. agno/models/anthropic/claude.py +183 -37
  111. agno/models/aws/bedrock.py +52 -112
  112. agno/models/aws/claude.py +33 -1
  113. agno/models/azure/ai_foundry.py +33 -15
  114. agno/models/azure/openai_chat.py +25 -8
  115. agno/models/base.py +1011 -566
  116. agno/models/cerebras/cerebras.py +19 -13
  117. agno/models/cerebras/cerebras_openai.py +8 -5
  118. agno/models/cohere/chat.py +27 -1
  119. agno/models/cometapi/__init__.py +5 -0
  120. agno/models/cometapi/cometapi.py +57 -0
  121. agno/models/dashscope/dashscope.py +1 -0
  122. agno/models/deepinfra/deepinfra.py +2 -2
  123. agno/models/deepseek/deepseek.py +2 -2
  124. agno/models/fireworks/fireworks.py +2 -2
  125. agno/models/google/gemini.py +110 -37
  126. agno/models/groq/groq.py +28 -11
  127. agno/models/huggingface/huggingface.py +2 -1
  128. agno/models/internlm/internlm.py +2 -2
  129. agno/models/langdb/langdb.py +4 -4
  130. agno/models/litellm/chat.py +18 -1
  131. agno/models/litellm/litellm_openai.py +2 -2
  132. agno/models/llama_cpp/__init__.py +5 -0
  133. agno/models/llama_cpp/llama_cpp.py +22 -0
  134. agno/models/message.py +143 -4
  135. agno/models/meta/llama.py +27 -10
  136. agno/models/meta/llama_openai.py +5 -17
  137. agno/models/nebius/nebius.py +6 -6
  138. agno/models/nexus/__init__.py +3 -0
  139. agno/models/nexus/nexus.py +22 -0
  140. agno/models/nvidia/nvidia.py +2 -2
  141. agno/models/ollama/chat.py +60 -6
  142. agno/models/openai/chat.py +102 -43
  143. agno/models/openai/responses.py +103 -106
  144. agno/models/openrouter/openrouter.py +41 -3
  145. agno/models/perplexity/perplexity.py +4 -5
  146. agno/models/portkey/portkey.py +3 -3
  147. agno/models/requesty/__init__.py +5 -0
  148. agno/models/requesty/requesty.py +52 -0
  149. agno/models/response.py +81 -5
  150. agno/models/sambanova/sambanova.py +2 -2
  151. agno/models/siliconflow/__init__.py +5 -0
  152. agno/models/siliconflow/siliconflow.py +25 -0
  153. agno/models/together/together.py +2 -2
  154. agno/models/utils.py +254 -8
  155. agno/models/vercel/v0.py +2 -2
  156. agno/models/vertexai/__init__.py +0 -0
  157. agno/models/vertexai/claude.py +96 -0
  158. agno/models/vllm/vllm.py +1 -0
  159. agno/models/xai/xai.py +3 -2
  160. agno/os/app.py +543 -175
  161. agno/os/auth.py +24 -14
  162. agno/os/config.py +1 -0
  163. agno/os/interfaces/__init__.py +1 -0
  164. agno/os/interfaces/a2a/__init__.py +3 -0
  165. agno/os/interfaces/a2a/a2a.py +42 -0
  166. agno/os/interfaces/a2a/router.py +250 -0
  167. agno/os/interfaces/a2a/utils.py +924 -0
  168. agno/os/interfaces/agui/agui.py +23 -7
  169. agno/os/interfaces/agui/router.py +27 -3
  170. agno/os/interfaces/agui/utils.py +242 -142
  171. agno/os/interfaces/base.py +6 -2
  172. agno/os/interfaces/slack/router.py +81 -23
  173. agno/os/interfaces/slack/slack.py +29 -14
  174. agno/os/interfaces/whatsapp/router.py +11 -4
  175. agno/os/interfaces/whatsapp/whatsapp.py +14 -7
  176. agno/os/mcp.py +111 -54
  177. agno/os/middleware/__init__.py +7 -0
  178. agno/os/middleware/jwt.py +233 -0
  179. agno/os/router.py +556 -139
  180. agno/os/routers/evals/evals.py +71 -34
  181. agno/os/routers/evals/schemas.py +31 -31
  182. agno/os/routers/evals/utils.py +6 -5
  183. agno/os/routers/health.py +31 -0
  184. agno/os/routers/home.py +52 -0
  185. agno/os/routers/knowledge/knowledge.py +185 -38
  186. agno/os/routers/knowledge/schemas.py +82 -22
  187. agno/os/routers/memory/memory.py +158 -53
  188. agno/os/routers/memory/schemas.py +20 -16
  189. agno/os/routers/metrics/metrics.py +20 -8
  190. agno/os/routers/metrics/schemas.py +16 -16
  191. agno/os/routers/session/session.py +499 -38
  192. agno/os/schema.py +308 -198
  193. agno/os/utils.py +401 -41
  194. agno/reasoning/anthropic.py +80 -0
  195. agno/reasoning/azure_ai_foundry.py +2 -2
  196. agno/reasoning/deepseek.py +2 -2
  197. agno/reasoning/default.py +3 -1
  198. agno/reasoning/gemini.py +73 -0
  199. agno/reasoning/groq.py +2 -2
  200. agno/reasoning/ollama.py +2 -2
  201. agno/reasoning/openai.py +7 -2
  202. agno/reasoning/vertexai.py +76 -0
  203. agno/run/__init__.py +6 -0
  204. agno/run/agent.py +266 -112
  205. agno/run/base.py +53 -24
  206. agno/run/team.py +252 -111
  207. agno/run/workflow.py +156 -45
  208. agno/session/agent.py +105 -89
  209. agno/session/summary.py +65 -25
  210. agno/session/team.py +176 -96
  211. agno/session/workflow.py +406 -40
  212. agno/team/team.py +3854 -1692
  213. agno/tools/brightdata.py +3 -3
  214. agno/tools/cartesia.py +3 -5
  215. agno/tools/dalle.py +9 -8
  216. agno/tools/decorator.py +4 -2
  217. agno/tools/desi_vocal.py +2 -2
  218. agno/tools/duckduckgo.py +15 -11
  219. agno/tools/e2b.py +20 -13
  220. agno/tools/eleven_labs.py +26 -28
  221. agno/tools/exa.py +21 -16
  222. agno/tools/fal.py +4 -4
  223. agno/tools/file.py +153 -23
  224. agno/tools/file_generation.py +350 -0
  225. agno/tools/firecrawl.py +4 -4
  226. agno/tools/function.py +257 -37
  227. agno/tools/giphy.py +2 -2
  228. agno/tools/gmail.py +238 -14
  229. agno/tools/google_drive.py +270 -0
  230. agno/tools/googlecalendar.py +36 -8
  231. agno/tools/googlesheets.py +20 -5
  232. agno/tools/jira.py +20 -0
  233. agno/tools/knowledge.py +3 -3
  234. agno/tools/lumalab.py +3 -3
  235. agno/tools/mcp/__init__.py +10 -0
  236. agno/tools/mcp/mcp.py +331 -0
  237. agno/tools/mcp/multi_mcp.py +347 -0
  238. agno/tools/mcp/params.py +24 -0
  239. agno/tools/mcp_toolbox.py +284 -0
  240. agno/tools/mem0.py +11 -17
  241. agno/tools/memori.py +1 -53
  242. agno/tools/memory.py +419 -0
  243. agno/tools/models/azure_openai.py +2 -2
  244. agno/tools/models/gemini.py +3 -3
  245. agno/tools/models/groq.py +3 -5
  246. agno/tools/models/nebius.py +7 -7
  247. agno/tools/models_labs.py +25 -15
  248. agno/tools/notion.py +204 -0
  249. agno/tools/openai.py +4 -9
  250. agno/tools/opencv.py +3 -3
  251. agno/tools/parallel.py +314 -0
  252. agno/tools/replicate.py +7 -7
  253. agno/tools/scrapegraph.py +58 -31
  254. agno/tools/searxng.py +2 -2
  255. agno/tools/serper.py +2 -2
  256. agno/tools/slack.py +18 -3
  257. agno/tools/spider.py +2 -2
  258. agno/tools/tavily.py +146 -0
  259. agno/tools/whatsapp.py +1 -1
  260. agno/tools/workflow.py +278 -0
  261. agno/tools/yfinance.py +12 -11
  262. agno/utils/agent.py +820 -0
  263. agno/utils/audio.py +27 -0
  264. agno/utils/common.py +90 -1
  265. agno/utils/events.py +222 -7
  266. agno/utils/gemini.py +181 -23
  267. agno/utils/hooks.py +57 -0
  268. agno/utils/http.py +111 -0
  269. agno/utils/knowledge.py +12 -5
  270. agno/utils/log.py +1 -0
  271. agno/utils/mcp.py +95 -5
  272. agno/utils/media.py +188 -10
  273. agno/utils/merge_dict.py +22 -1
  274. agno/utils/message.py +60 -0
  275. agno/utils/models/claude.py +40 -11
  276. agno/utils/models/cohere.py +1 -1
  277. agno/utils/models/watsonx.py +1 -1
  278. agno/utils/openai.py +1 -1
  279. agno/utils/print_response/agent.py +105 -21
  280. agno/utils/print_response/team.py +103 -38
  281. agno/utils/print_response/workflow.py +251 -34
  282. agno/utils/reasoning.py +22 -1
  283. agno/utils/serialize.py +32 -0
  284. agno/utils/streamlit.py +16 -10
  285. agno/utils/string.py +41 -0
  286. agno/utils/team.py +98 -9
  287. agno/utils/tools.py +1 -1
  288. agno/vectordb/base.py +23 -4
  289. agno/vectordb/cassandra/cassandra.py +65 -9
  290. agno/vectordb/chroma/chromadb.py +182 -38
  291. agno/vectordb/clickhouse/clickhousedb.py +64 -11
  292. agno/vectordb/couchbase/couchbase.py +105 -10
  293. agno/vectordb/lancedb/lance_db.py +183 -135
  294. agno/vectordb/langchaindb/langchaindb.py +25 -7
  295. agno/vectordb/lightrag/lightrag.py +17 -3
  296. agno/vectordb/llamaindex/__init__.py +3 -0
  297. agno/vectordb/llamaindex/llamaindexdb.py +46 -7
  298. agno/vectordb/milvus/milvus.py +126 -9
  299. agno/vectordb/mongodb/__init__.py +7 -1
  300. agno/vectordb/mongodb/mongodb.py +112 -7
  301. agno/vectordb/pgvector/pgvector.py +142 -21
  302. agno/vectordb/pineconedb/pineconedb.py +80 -8
  303. agno/vectordb/qdrant/qdrant.py +125 -39
  304. agno/vectordb/redis/__init__.py +9 -0
  305. agno/vectordb/redis/redisdb.py +694 -0
  306. agno/vectordb/singlestore/singlestore.py +111 -25
  307. agno/vectordb/surrealdb/surrealdb.py +31 -5
  308. agno/vectordb/upstashdb/upstashdb.py +76 -8
  309. agno/vectordb/weaviate/weaviate.py +86 -15
  310. agno/workflow/__init__.py +2 -0
  311. agno/workflow/agent.py +299 -0
  312. agno/workflow/condition.py +112 -18
  313. agno/workflow/loop.py +69 -10
  314. agno/workflow/parallel.py +266 -118
  315. agno/workflow/router.py +110 -17
  316. agno/workflow/step.py +645 -136
  317. agno/workflow/steps.py +65 -6
  318. agno/workflow/types.py +71 -33
  319. agno/workflow/workflow.py +2113 -300
  320. agno-2.3.0.dist-info/METADATA +618 -0
  321. agno-2.3.0.dist-info/RECORD +577 -0
  322. agno-2.3.0.dist-info/licenses/LICENSE +201 -0
  323. agno/knowledge/reader/url_reader.py +0 -128
  324. agno/tools/googlesearch.py +0 -98
  325. agno/tools/mcp.py +0 -610
  326. agno/utils/models/aws_claude.py +0 -170
  327. agno-2.0.0rc2.dist-info/METADATA +0 -355
  328. agno-2.0.0rc2.dist-info/RECORD +0 -515
  329. agno-2.0.0rc2.dist-info/licenses/LICENSE +0 -375
  330. {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/WHEEL +0 -0
  331. {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/top_level.txt +0 -0
agno/tools/brightdata.py CHANGED
@@ -5,7 +5,7 @@ from typing import Any, Dict, List, Optional
5
5
  from uuid import uuid4
6
6
 
7
7
  from agno.agent import Agent
8
- from agno.media import ImageArtifact
8
+ from agno.media import Image
9
9
  from agno.tools import Toolkit
10
10
  from agno.tools.function import ToolResult
11
11
  from agno.utils.log import log_debug, log_error, log_info
@@ -158,8 +158,8 @@ class BrightDataTools(Toolkit):
158
158
 
159
159
  media_id = str(uuid4())
160
160
 
161
- # Create ImageArtifact for the screenshot
162
- image_artifact = ImageArtifact(
161
+ # Create Image for the screenshot
162
+ image_artifact = Image(
163
163
  id=media_id,
164
164
  content=base64_encoded_image.encode("utf-8"),
165
165
  mime_type="image/png",
agno/tools/cartesia.py CHANGED
@@ -1,11 +1,10 @@
1
1
  import json
2
- from base64 import b64encode
3
2
  from os import getenv
4
3
  from typing import Any, Dict, List, Optional, Union
5
4
  from uuid import uuid4
6
5
 
7
6
  from agno.agent import Agent
8
- from agno.media import AudioArtifact
7
+ from agno.media import Audio
9
8
  from agno.team.team import Team
10
9
  from agno.tools import Toolkit
11
10
  from agno.tools.function import ToolResult
@@ -170,12 +169,11 @@ class CartesiaTools(Toolkit):
170
169
 
171
170
  audio_iterator = self.client.tts.bytes(**params)
172
171
  audio_data = b"".join(chunk for chunk in audio_iterator)
173
- base64_audio = b64encode(audio_data).decode("utf-8")
174
172
 
175
173
  # Create AudioArtifact
176
- audio_artifact = AudioArtifact(
174
+ audio_artifact = Audio(
177
175
  id=str(uuid4()),
178
- base64_audio=base64_audio,
176
+ content=audio_data,
179
177
  mime_type=mime_type, # Hardcoded to audio/mpeg
180
178
  )
181
179
 
agno/tools/dalle.py CHANGED
@@ -1,10 +1,8 @@
1
1
  from os import getenv
2
- from typing import Any, List, Literal, Optional, Union
2
+ from typing import Any, List, Literal, Optional
3
3
  from uuid import uuid4
4
4
 
5
- from agno.agent import Agent
6
- from agno.media import ImageArtifact
7
- from agno.team.team import Team
5
+ from agno.media import Image
8
6
  from agno.tools import Toolkit
9
7
  from agno.tools.function import ToolResult
10
8
  from agno.utils.log import log_debug, logger
@@ -64,7 +62,7 @@ class DalleTools(Toolkit):
64
62
  # - Add support for saving images
65
63
  # - Add support for editing images
66
64
 
67
- def create_image(self, agent: Union[Agent, Team], prompt: str) -> ToolResult:
65
+ def create_image(self, prompt: str) -> ToolResult:
68
66
  """Use this function to generate an image for a prompt.
69
67
 
70
68
  Args:
@@ -94,10 +92,13 @@ class DalleTools(Toolkit):
94
92
  if response.data:
95
93
  for img in response.data:
96
94
  if img.url:
97
- image_artifact = ImageArtifact(
98
- id=str(uuid4()), url=img.url, original_prompt=prompt, revised_prompt=img.revised_prompt
95
+ image = Image(
96
+ id=str(uuid4()),
97
+ url=img.url,
98
+ original_prompt=prompt,
99
+ revised_prompt=img.revised_prompt,
99
100
  )
100
- generated_images.append(image_artifact)
101
+ generated_images.append(image)
101
102
  response_str += f"Image has been generated at the URL {img.url}\n"
102
103
 
103
104
  return ToolResult(
agno/tools/decorator.py CHANGED
@@ -250,8 +250,10 @@ def tool(*args, **kwargs) -> Union[Function, Callable[[F], Function]]:
250
250
  if kwargs.get("stop_after_tool_call") is True:
251
251
  if "show_result" not in kwargs or kwargs.get("show_result") is None:
252
252
  tool_config["show_result"] = True
253
-
254
- return Function(**tool_config)
253
+ function = Function(**tool_config)
254
+ # Determine parameters for the function
255
+ function.process_entrypoint()
256
+ return function
255
257
 
256
258
  # Handle both @tool and @tool() cases
257
259
  if len(args) == 1 and callable(args[0]) and not kwargs:
agno/tools/desi_vocal.py CHANGED
@@ -5,7 +5,7 @@ from uuid import uuid4
5
5
  import requests
6
6
 
7
7
  from agno.agent import Agent
8
- from agno.media import AudioArtifact
8
+ from agno.media import Audio
9
9
  from agno.team.team import Team
10
10
  from agno.tools import Toolkit
11
11
  from agno.tools.function import ToolResult
@@ -97,7 +97,7 @@ class DesiVocalTools(Toolkit):
97
97
  response_json = response.json()
98
98
  audio_url = response_json["s3_path"]
99
99
 
100
- audio_artifact = AudioArtifact(id=str(uuid4()), url=audio_url)
100
+ audio_artifact = Audio(id=str(uuid4()), url=audio_url)
101
101
 
102
102
  return ToolResult(
103
103
  content=f"Audio generated successfully: {audio_url}",
agno/tools/duckduckgo.py CHANGED
@@ -12,14 +12,16 @@ except ImportError:
12
12
 
13
13
  class DuckDuckGoTools(Toolkit):
14
14
  """
15
- DuckDuckGo is a toolkit for searching DuckDuckGo easily.
15
+ DuckDuckGo is a toolkit for searching using DuckDuckGo easily.
16
+ It uses the meta-search library DDGS, so it also has access to other backends.
16
17
  Args:
17
- search (bool): Enable DuckDuckGo search function.
18
- news (bool): Enable DuckDuckGo news function.
18
+ enable_search (bool): Enable DDGS search function.
19
+ enable_news (bool): Enable DDGS news function.
19
20
  modifier (Optional[str]): A modifier to be used in the search request.
20
21
  fixed_max_results (Optional[int]): A fixed number of maximum results.
21
22
  proxy (Optional[str]): Proxy to be used in the search request.
22
23
  timeout (Optional[int]): The maximum number of seconds to wait for a response.
24
+ backend (Optional[str]): The backend to be used in the search request.
23
25
 
24
26
  """
25
27
 
@@ -28,6 +30,7 @@ class DuckDuckGoTools(Toolkit):
28
30
  enable_search: bool = True,
29
31
  enable_news: bool = True,
30
32
  all: bool = False,
33
+ backend: str = "duckduckgo",
31
34
  modifier: Optional[str] = None,
32
35
  fixed_max_results: Optional[int] = None,
33
36
  proxy: Optional[str] = None,
@@ -40,6 +43,7 @@ class DuckDuckGoTools(Toolkit):
40
43
  self.fixed_max_results: Optional[int] = fixed_max_results
41
44
  self.modifier: Optional[str] = modifier
42
45
  self.verify_ssl: bool = verify_ssl
46
+ self.backend: str = backend
43
47
 
44
48
  tools: List[Any] = []
45
49
  if all or enable_search:
@@ -50,38 +54,38 @@ class DuckDuckGoTools(Toolkit):
50
54
  super().__init__(name="duckduckgo", tools=tools, **kwargs)
51
55
 
52
56
  def duckduckgo_search(self, query: str, max_results: int = 5) -> str:
53
- """Use this function to search DuckDuckGo for a query.
57
+ """Use this function to search DDGS for a query.
54
58
 
55
59
  Args:
56
60
  query(str): The query to search for.
57
61
  max_results (optional, default=5): The maximum number of results to return.
58
62
 
59
63
  Returns:
60
- The result from DuckDuckGo.
64
+ The result from DDGS.
61
65
  """
62
66
  actual_max_results = self.fixed_max_results or max_results
63
67
  search_query = f"{self.modifier} {query}" if self.modifier else query
64
68
 
65
- log_debug(f"Searching DDG for: {search_query}")
69
+ log_debug(f"Searching DDG for: {search_query} using backend: {self.backend}")
66
70
  with DDGS(proxy=self.proxy, timeout=self.timeout, verify=self.verify_ssl) as ddgs:
67
- results = ddgs.text(query=search_query, max_results=actual_max_results)
71
+ results = ddgs.text(query=search_query, max_results=actual_max_results, backend=self.backend)
68
72
 
69
73
  return json.dumps(results, indent=2)
70
74
 
71
75
  def duckduckgo_news(self, query: str, max_results: int = 5) -> str:
72
- """Use this function to get the latest news from DuckDuckGo.
76
+ """Use this function to get the latest news from DDGS.
73
77
 
74
78
  Args:
75
79
  query(str): The query to search for.
76
80
  max_results (optional, default=5): The maximum number of results to return.
77
81
 
78
82
  Returns:
79
- The latest news from DuckDuckGo.
83
+ The latest news from DDGS.
80
84
  """
81
85
  actual_max_results = self.fixed_max_results or max_results
82
86
 
83
- log_debug(f"Searching DDG news for: {query}")
87
+ log_debug(f"Searching DDG news for: {query} using backend: {self.backend}")
84
88
  with DDGS(proxy=self.proxy, timeout=self.timeout, verify=self.verify_ssl) as ddgs:
85
- results = ddgs.news(query=query, max_results=actual_max_results)
89
+ results = ddgs.news(query=query, max_results=actual_max_results, backend=self.backend)
86
90
 
87
91
  return json.dumps(results, indent=2)
agno/tools/e2b.py CHANGED
@@ -8,7 +8,7 @@ from typing import Any, Callable, Dict, List, Optional, Union
8
8
  from uuid import uuid4
9
9
 
10
10
  from agno.agent import Agent
11
- from agno.media import ImageArtifact
11
+ from agno.media import Image
12
12
  from agno.team.team import Team
13
13
  from agno.tools import Toolkit
14
14
  from agno.tools.function import ToolResult
@@ -161,7 +161,7 @@ class E2BTools(Toolkit):
161
161
  self, agent: Union[Agent, Team], result_index: int = 0, output_path: Optional[str] = None
162
162
  ) -> ToolResult:
163
163
  """
164
- Add a PNG image result from the last code execution as an ImageArtifact.
164
+ Add a PNG image result from the last code execution as an Image object.
165
165
 
166
166
  Args:
167
167
  agent: The agent to add the image artifact to
@@ -205,9 +205,9 @@ class E2BTools(Toolkit):
205
205
  # Generate a file:// URL for the temp file
206
206
  file_url = f"file://{temp_path}"
207
207
 
208
- # Create ImageArtifact
208
+ # Create Image object
209
209
  image_id = str(uuid4())
210
- image_artifact = ImageArtifact(
210
+ image_artifact = Image(
211
211
  id=image_id, url=file_url, original_prompt=f"Generated from code execution result {result_index}"
212
212
  )
213
213
 
@@ -292,9 +292,9 @@ class E2BTools(Toolkit):
292
292
  # Generate a file:// URL for the temp file
293
293
  file_url = f"file://{temp_path}"
294
294
 
295
- # Create ImageArtifact
295
+ # Create Image object
296
296
  image_id = str(uuid4())
297
- image_artifact = ImageArtifact(
297
+ image_artifact = Image(
298
298
  id=image_id, url=file_url, original_prompt=f"Interactive {chart_type} chart from code execution"
299
299
  )
300
300
 
@@ -464,7 +464,7 @@ class E2BTools(Toolkit):
464
464
 
465
465
  result = f"Contents of {directory_path}:\n"
466
466
  for file in files:
467
- file_type = "Directory" if file.is_dir else "File"
467
+ file_type = "Directory" if file.type == "directory" else "File"
468
468
  size = f"{file.size} bytes" if file.size is not None else "Unknown size"
469
469
  result += f"- {file.name} ({file_type}, {size})\n"
470
470
 
@@ -486,12 +486,19 @@ class E2BTools(Toolkit):
486
486
  try:
487
487
  content = self.sandbox.files.read(file_path)
488
488
 
489
- # Try to decode as text if encoding is provided
490
- try:
491
- text_content = content.decode(encoding)
492
- return text_content
493
- except UnicodeDecodeError:
494
- return f"File read successfully but contains binary data ({len(content)} bytes). Use download_file_from_sandbox to save it."
489
+ # Check if content is already a string or if it's bytes that need decoding
490
+ if isinstance(content, str):
491
+ return content
492
+ elif isinstance(content, bytes):
493
+ # Try to decode as text if encoding is provided
494
+ try:
495
+ text_content = content.decode(encoding)
496
+ return text_content
497
+ except UnicodeDecodeError:
498
+ return f"File read successfully but contains binary data ({len(content)} bytes). Use download_file_from_sandbox to save it."
499
+ else:
500
+ # Handle unexpected content type
501
+ return f"Unexpected content type: {type(content)}. Expected str or bytes."
495
502
 
496
503
  except Exception as e:
497
504
  return json.dumps({"status": "error", "message": f"Error reading file: {str(e)}"})
agno/tools/eleven_labs.py CHANGED
@@ -1,4 +1,3 @@
1
- from base64 import b64encode
2
1
  from io import BytesIO
3
2
  from os import getenv, path
4
3
  from pathlib import Path
@@ -6,11 +5,11 @@ from typing import Any, Iterator, List, Literal, Optional, Union
6
5
  from uuid import uuid4
7
6
 
8
7
  from agno.agent import Agent
9
- from agno.media import AudioArtifact
8
+ from agno.media import Audio
10
9
  from agno.team.team import Team
11
10
  from agno.tools import Toolkit
12
11
  from agno.tools.function import ToolResult
13
- from agno.utils.log import logger
12
+ from agno.utils.log import log_error, log_info
14
13
 
15
14
  try:
16
15
  from elevenlabs import ElevenLabs # type: ignore
@@ -48,7 +47,7 @@ class ElevenLabsTools(Toolkit):
48
47
  ):
49
48
  self.api_key = api_key or getenv("ELEVEN_LABS_API_KEY")
50
49
  if not self.api_key:
51
- logger.error("ELEVEN_LABS_API_KEY not set. Please set the ELEVEN_LABS_API_KEY environment variable.")
50
+ log_error("ELEVEN_LABS_API_KEY not set. Please set the ELEVEN_LABS_API_KEY environment variable.")
52
51
 
53
52
  self.target_directory = target_directory
54
53
  self.voice_id = voice_id
@@ -73,7 +72,7 @@ class ElevenLabsTools(Toolkit):
73
72
 
74
73
  def get_voices(self) -> str:
75
74
  """
76
- Use this function to get all the voices available.
75
+ Get all the voices available.
77
76
 
78
77
  Returns:
79
78
  result (list): A list of voices that have an ID, name and description.
@@ -94,20 +93,19 @@ class ElevenLabsTools(Toolkit):
94
93
  return str(response)
95
94
 
96
95
  except Exception as e:
97
- logger.error(f"Failed to fetch voices: {e}")
96
+ log_error(f"Failed to fetch voices: {e}")
98
97
  return f"Error: {e}"
99
98
 
100
- def _process_audio(self, audio_generator: Iterator[bytes]) -> str:
101
- # Step 1: Write audio data to BytesIO
99
+ def _process_audio(self, audio_generator: Iterator[bytes]) -> bytes:
102
100
  audio_bytes = BytesIO()
103
101
  for chunk in audio_generator:
104
102
  audio_bytes.write(chunk)
105
- audio_bytes.seek(0) # Rewind the stream
106
103
 
107
- # Step 2: Encode as Base64
108
- base64_audio = b64encode(audio_bytes.read()).decode("utf-8")
104
+ # Read bytes
105
+ audio_bytes.seek(0)
106
+ audio_data = audio_bytes.read()
109
107
 
110
- # Step 3: Optionally save to disk if target_directory exists
108
+ # Save to disk if target_directory exists
111
109
  if self.target_directory:
112
110
  # Determine file extension based on output format
113
111
  if self.output_format.startswith("mp3"):
@@ -122,19 +120,19 @@ class ElevenLabsTools(Toolkit):
122
120
  output_filename = f"{uuid4()}.{extension}"
123
121
  output_path = path.join(self.target_directory, output_filename)
124
122
 
125
- # Write from BytesIO to disk
126
- audio_bytes.seek(0) # Reset the BytesIO stream again
127
123
  with open(output_path, "wb") as f:
128
- f.write(audio_bytes.read())
124
+ f.write(audio_data)
129
125
 
130
- return base64_audio
126
+ log_info(f"Audio saved to: {output_path}")
127
+
128
+ return audio_data
131
129
 
132
130
  def generate_sound_effect(self, prompt: str, duration_seconds: Optional[float] = None) -> ToolResult:
133
131
  """
134
- Use this function to generate sound effect audio from a text prompt.
132
+ Generate a sound effect from a text description.
135
133
 
136
134
  Args:
137
- prompt (str): Text to generate audio from.
135
+ prompt (str): Description of the sound effect
138
136
  duration_seconds (Optional[float]): Duration in seconds to generate audio from. Has to be between 0.5 and 22.
139
137
  Returns:
140
138
  ToolResult: A ToolResult containing the generated audio or error message.
@@ -144,27 +142,27 @@ class ElevenLabsTools(Toolkit):
144
142
  text=prompt, duration_seconds=duration_seconds
145
143
  )
146
144
 
147
- base64_audio = self._process_audio(audio_generator)
145
+ audio_data = self._process_audio(audio_generator)
148
146
 
149
147
  # Create AudioArtifact
150
- audio_artifact = AudioArtifact(
148
+ audio_artifact = Audio(
151
149
  id=str(uuid4()),
152
- base64_audio=base64_audio,
150
+ content=audio_data,
153
151
  mime_type="audio/mpeg",
154
152
  )
155
153
 
156
154
  return ToolResult(
157
- content="Audio generated successfully",
155
+ content="Sound effect generated successfully",
158
156
  audios=[audio_artifact],
159
157
  )
160
158
 
161
159
  except Exception as e:
162
- logger.error(f"Failed to generate audio: {e}")
160
+ log_error(f"Failed to generate sound effect: {e}")
163
161
  return ToolResult(content=f"Error: {e}")
164
162
 
165
163
  def text_to_speech(self, agent: Union[Agent, Team], prompt: str) -> ToolResult:
166
164
  """
167
- Use this function to convert text to speech audio.
165
+ Convert text to speech.
168
166
 
169
167
  Args:
170
168
  prompt (str): Text to generate audio from.
@@ -179,12 +177,12 @@ class ElevenLabsTools(Toolkit):
179
177
  output_format=self.output_format,
180
178
  )
181
179
 
182
- base64_audio = self._process_audio(audio_generator)
180
+ audio_data = self._process_audio(audio_generator)
183
181
 
184
182
  # Create AudioArtifact
185
- audio_artifact = AudioArtifact(
183
+ audio_artifact = Audio(
186
184
  id=str(uuid4()),
187
- base64_audio=base64_audio,
185
+ content=audio_data,
188
186
  mime_type="audio/mpeg",
189
187
  )
190
188
 
@@ -194,5 +192,5 @@ class ElevenLabsTools(Toolkit):
194
192
  )
195
193
 
196
194
  except Exception as e:
197
- logger.error(f"Failed to generate audio: {e}")
195
+ log_error(f"Failed to generate audio: {e}")
198
196
  return ToolResult(content=f"Error: {e}")
agno/tools/exa.py CHANGED
@@ -27,14 +27,14 @@ class ExaTools(Toolkit):
27
27
  all (bool): Enable all tools. Overrides individual flags when True. Default is False.
28
28
  text (bool): Retrieve text content from results. Default is True.
29
29
  text_length_limit (int): Max length of text content per result. Default is 1000.
30
- highlights (bool): Include highlighted snippets. Default is True.
30
+ highlights (bool): Include highlighted snippets. Deprecated since it was removed in the Exa API. It will be removed from Agno in a future release.
31
31
  api_key (Optional[str]): Exa API key. Retrieved from `EXA_API_KEY` env variable if not provided.
32
32
  num_results (Optional[int]): Default number of search results. Overrides individual searches if set.
33
33
  start_crawl_date (Optional[str]): Include results crawled on/after this date (`YYYY-MM-DD`).
34
34
  end_crawl_date (Optional[str]): Include results crawled on/before this date (`YYYY-MM-DD`).
35
35
  start_published_date (Optional[str]): Include results published on/after this date (`YYYY-MM-DD`).
36
36
  end_published_date (Optional[str]): Include results published on/before this date (`YYYY-MM-DD`).
37
- use_autoprompt (Optional[bool]): Enable autoprompt features in queries.
37
+ use_autoprompt (Optional[bool]): Enable autoprompt features in queries. Deprecated since it was removed in the Exa API. It will be removed from Agno in a future release.
38
38
  type (Optional[str]): Specify content type (e.g., article, blog, video).
39
39
  category (Optional[str]): Filter results by category. Options are "company", "research paper", "news", "pdf", "github", "tweet", "personal site", "linkedin profile", "financial report".
40
40
  include_domains (Optional[List[str]]): Restrict results to these domains.
@@ -54,7 +54,7 @@ class ExaTools(Toolkit):
54
54
  all: bool = False,
55
55
  text: bool = True,
56
56
  text_length_limit: int = 1000,
57
- highlights: bool = True,
57
+ highlights: Optional[bool] = None, # Deprecated
58
58
  summary: bool = False,
59
59
  api_key: Optional[str] = None,
60
60
  num_results: Optional[int] = None,
@@ -84,7 +84,24 @@ class ExaTools(Toolkit):
84
84
 
85
85
  self.text: bool = text
86
86
  self.text_length_limit: int = text_length_limit
87
- self.highlights: bool = highlights
87
+
88
+ if highlights:
89
+ import warnings
90
+
91
+ warnings.warn(
92
+ "The 'highlights' parameter is deprecated since it was removed in the Exa API. It will be removed from Agno in a future release.",
93
+ DeprecationWarning,
94
+ stacklevel=2,
95
+ )
96
+ if use_autoprompt:
97
+ import warnings
98
+
99
+ warnings.warn(
100
+ "The 'use_autoprompt' parameter is deprecated since it was removed in the Exa API. It will be removed from Agno in a future release.",
101
+ DeprecationWarning,
102
+ stacklevel=2,
103
+ )
104
+
88
105
  self.summary: bool = summary
89
106
  self.num_results: Optional[int] = num_results
90
107
  self.livecrawl: str = livecrawl
@@ -92,7 +109,6 @@ class ExaTools(Toolkit):
92
109
  self.end_crawl_date: Optional[str] = end_crawl_date
93
110
  self.start_published_date: Optional[str] = start_published_date
94
111
  self.end_published_date: Optional[str] = end_published_date
95
- self.use_autoprompt: Optional[bool] = use_autoprompt
96
112
  self.type: Optional[str] = type
97
113
  self.category: Optional[str] = category
98
114
  self.include_domains: Optional[List[str]] = include_domains
@@ -140,13 +156,6 @@ class ExaTools(Toolkit):
140
156
  if self.text_length_limit:
141
157
  _text = _text[: self.text_length_limit]
142
158
  result_dict["text"] = _text
143
- if self.highlights:
144
- try:
145
- if result.highlights: # type: ignore
146
- result_dict["highlights"] = result.highlights # type: ignore
147
- except Exception as e:
148
- log_debug(f"Failed to get highlights {e}")
149
- result_dict["highlights"] = f"Failed to get highlights {e}"
150
159
  exa_results_parsed.append(result_dict)
151
160
  return json.dumps(exa_results_parsed, indent=4, ensure_ascii=False)
152
161
 
@@ -168,14 +177,12 @@ class ExaTools(Toolkit):
168
177
  log_info(f"Searching exa for: {query}")
169
178
  search_kwargs: Dict[str, Any] = {
170
179
  "text": self.text,
171
- "highlights": self.highlights,
172
180
  "summary": self.summary,
173
181
  "num_results": self.num_results or num_results,
174
182
  "start_crawl_date": self.start_crawl_date,
175
183
  "end_crawl_date": self.end_crawl_date,
176
184
  "start_published_date": self.start_published_date,
177
185
  "end_published_date": self.end_published_date,
178
- "use_autoprompt": self.use_autoprompt,
179
186
  "type": self.type,
180
187
  "category": self.category or category, # Prefer a user-set category
181
188
  "include_domains": self.include_domains,
@@ -212,7 +219,6 @@ class ExaTools(Toolkit):
212
219
 
213
220
  query_kwargs: Dict[str, Any] = {
214
221
  "text": self.text,
215
- "highlights": self.highlights,
216
222
  "summary": self.summary,
217
223
  }
218
224
 
@@ -249,7 +255,6 @@ class ExaTools(Toolkit):
249
255
 
250
256
  query_kwargs: Dict[str, Any] = {
251
257
  "text": self.text,
252
- "highlights": self.highlights,
253
258
  "summary": self.summary,
254
259
  "include_domains": self.include_domains,
255
260
  "exclude_domains": self.exclude_domains,
agno/tools/fal.py CHANGED
@@ -7,7 +7,7 @@ from typing import Optional, Union
7
7
  from uuid import uuid4
8
8
 
9
9
  from agno.agent import Agent
10
- from agno.media import ImageArtifact, VideoArtifact
10
+ from agno.media import Image, Video
11
11
  from agno.team.team import Team
12
12
  from agno.tools import Toolkit
13
13
  from agno.tools.function import ToolResult
@@ -72,14 +72,14 @@ class FalTools(Toolkit):
72
72
 
73
73
  if "image" in result:
74
74
  url = result.get("image", {}).get("url", "")
75
- image_artifact = ImageArtifact(
75
+ image_artifact = Image(
76
76
  id=media_id,
77
77
  url=url,
78
78
  )
79
79
  return ToolResult(content=f"Image generated successfully at {url}", images=[image_artifact])
80
80
  elif "video" in result:
81
81
  url = result.get("video", {}).get("url", "")
82
- video_artifact = VideoArtifact(
82
+ video_artifact = Video(
83
83
  id=media_id,
84
84
  url=url,
85
85
  )
@@ -115,7 +115,7 @@ class FalTools(Toolkit):
115
115
  )
116
116
  url = result.get("images", [{}])[0].get("url", "")
117
117
  media_id = str(uuid4())
118
- image_artifact = ImageArtifact(
118
+ image_artifact = Image(
119
119
  id=media_id,
120
120
  url=url,
121
121
  )