agno 0.1.2__py3-none-any.whl → 2.3.13__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 (723) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +44 -5
  3. agno/agent/agent.py +10531 -2975
  4. agno/api/agent.py +14 -53
  5. agno/api/api.py +7 -46
  6. agno/api/evals.py +22 -0
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -25
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +6 -9
  11. agno/api/schemas/evals.py +16 -0
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +10 -10
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +16 -0
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +22 -26
  18. agno/api/workflow.py +28 -0
  19. agno/cloud/aws/base.py +214 -0
  20. agno/cloud/aws/s3/__init__.py +2 -0
  21. agno/cloud/aws/s3/api_client.py +43 -0
  22. agno/cloud/aws/s3/bucket.py +195 -0
  23. agno/cloud/aws/s3/object.py +57 -0
  24. agno/compression/__init__.py +3 -0
  25. agno/compression/manager.py +247 -0
  26. agno/culture/__init__.py +3 -0
  27. agno/culture/manager.py +956 -0
  28. agno/db/__init__.py +24 -0
  29. agno/db/async_postgres/__init__.py +3 -0
  30. agno/db/base.py +946 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2781 -0
  33. agno/db/dynamo/schemas.py +442 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +2379 -0
  37. agno/db/firestore/schemas.py +181 -0
  38. agno/db/firestore/utils.py +376 -0
  39. agno/db/gcs_json/__init__.py +3 -0
  40. agno/db/gcs_json/gcs_json_db.py +1791 -0
  41. agno/db/gcs_json/utils.py +228 -0
  42. agno/db/in_memory/__init__.py +3 -0
  43. agno/db/in_memory/in_memory_db.py +1312 -0
  44. agno/db/in_memory/utils.py +230 -0
  45. agno/db/json/__init__.py +3 -0
  46. agno/db/json/json_db.py +1777 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/manager.py +199 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/migrations/versions/v2_3_0.py +938 -0
  51. agno/db/mongo/__init__.py +17 -0
  52. agno/db/mongo/async_mongo.py +2760 -0
  53. agno/db/mongo/mongo.py +2597 -0
  54. agno/db/mongo/schemas.py +119 -0
  55. agno/db/mongo/utils.py +276 -0
  56. agno/db/mysql/__init__.py +4 -0
  57. agno/db/mysql/async_mysql.py +2912 -0
  58. agno/db/mysql/mysql.py +2923 -0
  59. agno/db/mysql/schemas.py +186 -0
  60. agno/db/mysql/utils.py +488 -0
  61. agno/db/postgres/__init__.py +4 -0
  62. agno/db/postgres/async_postgres.py +2579 -0
  63. agno/db/postgres/postgres.py +2870 -0
  64. agno/db/postgres/schemas.py +187 -0
  65. agno/db/postgres/utils.py +442 -0
  66. agno/db/redis/__init__.py +3 -0
  67. agno/db/redis/redis.py +2141 -0
  68. agno/db/redis/schemas.py +159 -0
  69. agno/db/redis/utils.py +346 -0
  70. agno/db/schemas/__init__.py +4 -0
  71. agno/db/schemas/culture.py +120 -0
  72. agno/db/schemas/evals.py +34 -0
  73. agno/db/schemas/knowledge.py +40 -0
  74. agno/db/schemas/memory.py +61 -0
  75. agno/db/singlestore/__init__.py +3 -0
  76. agno/db/singlestore/schemas.py +179 -0
  77. agno/db/singlestore/singlestore.py +2877 -0
  78. agno/db/singlestore/utils.py +384 -0
  79. agno/db/sqlite/__init__.py +4 -0
  80. agno/db/sqlite/async_sqlite.py +2911 -0
  81. agno/db/sqlite/schemas.py +181 -0
  82. agno/db/sqlite/sqlite.py +2908 -0
  83. agno/db/sqlite/utils.py +429 -0
  84. agno/db/surrealdb/__init__.py +3 -0
  85. agno/db/surrealdb/metrics.py +292 -0
  86. agno/db/surrealdb/models.py +334 -0
  87. agno/db/surrealdb/queries.py +71 -0
  88. agno/db/surrealdb/surrealdb.py +1908 -0
  89. agno/db/surrealdb/utils.py +147 -0
  90. agno/db/utils.py +118 -0
  91. agno/eval/__init__.py +24 -0
  92. agno/eval/accuracy.py +666 -276
  93. agno/eval/agent_as_judge.py +861 -0
  94. agno/eval/base.py +29 -0
  95. agno/eval/performance.py +779 -0
  96. agno/eval/reliability.py +241 -62
  97. agno/eval/utils.py +120 -0
  98. agno/exceptions.py +143 -1
  99. agno/filters.py +354 -0
  100. agno/guardrails/__init__.py +6 -0
  101. agno/guardrails/base.py +19 -0
  102. agno/guardrails/openai.py +144 -0
  103. agno/guardrails/pii.py +94 -0
  104. agno/guardrails/prompt_injection.py +52 -0
  105. agno/hooks/__init__.py +3 -0
  106. agno/hooks/decorator.py +164 -0
  107. agno/integrations/discord/__init__.py +3 -0
  108. agno/integrations/discord/client.py +203 -0
  109. agno/knowledge/__init__.py +5 -1
  110. agno/{document → knowledge}/chunking/agentic.py +22 -14
  111. agno/{document → knowledge}/chunking/document.py +2 -2
  112. agno/{document → knowledge}/chunking/fixed.py +7 -6
  113. agno/knowledge/chunking/markdown.py +151 -0
  114. agno/{document → knowledge}/chunking/recursive.py +15 -3
  115. agno/knowledge/chunking/row.py +39 -0
  116. agno/knowledge/chunking/semantic.py +91 -0
  117. agno/knowledge/chunking/strategy.py +165 -0
  118. agno/knowledge/content.py +74 -0
  119. agno/knowledge/document/__init__.py +5 -0
  120. agno/{document → knowledge/document}/base.py +12 -2
  121. agno/knowledge/embedder/__init__.py +5 -0
  122. agno/knowledge/embedder/aws_bedrock.py +343 -0
  123. agno/knowledge/embedder/azure_openai.py +210 -0
  124. agno/{embedder → knowledge/embedder}/base.py +8 -0
  125. agno/knowledge/embedder/cohere.py +323 -0
  126. agno/knowledge/embedder/fastembed.py +62 -0
  127. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  128. agno/knowledge/embedder/google.py +258 -0
  129. agno/knowledge/embedder/huggingface.py +94 -0
  130. agno/knowledge/embedder/jina.py +182 -0
  131. agno/knowledge/embedder/langdb.py +22 -0
  132. agno/knowledge/embedder/mistral.py +206 -0
  133. agno/knowledge/embedder/nebius.py +13 -0
  134. agno/knowledge/embedder/ollama.py +154 -0
  135. agno/knowledge/embedder/openai.py +195 -0
  136. agno/knowledge/embedder/sentence_transformer.py +63 -0
  137. agno/{embedder → knowledge/embedder}/together.py +1 -1
  138. agno/knowledge/embedder/vllm.py +262 -0
  139. agno/knowledge/embedder/voyageai.py +165 -0
  140. agno/knowledge/knowledge.py +3006 -0
  141. agno/knowledge/reader/__init__.py +7 -0
  142. agno/knowledge/reader/arxiv_reader.py +81 -0
  143. agno/knowledge/reader/base.py +95 -0
  144. agno/knowledge/reader/csv_reader.py +164 -0
  145. agno/knowledge/reader/docx_reader.py +82 -0
  146. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  147. agno/knowledge/reader/firecrawl_reader.py +201 -0
  148. agno/knowledge/reader/json_reader.py +88 -0
  149. agno/knowledge/reader/markdown_reader.py +137 -0
  150. agno/knowledge/reader/pdf_reader.py +431 -0
  151. agno/knowledge/reader/pptx_reader.py +101 -0
  152. agno/knowledge/reader/reader_factory.py +313 -0
  153. agno/knowledge/reader/s3_reader.py +89 -0
  154. agno/knowledge/reader/tavily_reader.py +193 -0
  155. agno/knowledge/reader/text_reader.py +127 -0
  156. agno/knowledge/reader/web_search_reader.py +325 -0
  157. agno/knowledge/reader/website_reader.py +455 -0
  158. agno/knowledge/reader/wikipedia_reader.py +91 -0
  159. agno/knowledge/reader/youtube_reader.py +78 -0
  160. agno/knowledge/remote_content/remote_content.py +88 -0
  161. agno/knowledge/reranker/__init__.py +3 -0
  162. agno/{reranker → knowledge/reranker}/base.py +1 -1
  163. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  164. agno/knowledge/reranker/infinity.py +195 -0
  165. agno/knowledge/reranker/sentence_transformer.py +54 -0
  166. agno/knowledge/types.py +39 -0
  167. agno/knowledge/utils.py +234 -0
  168. agno/media.py +439 -95
  169. agno/memory/__init__.py +16 -3
  170. agno/memory/manager.py +1474 -123
  171. agno/memory/strategies/__init__.py +15 -0
  172. agno/memory/strategies/base.py +66 -0
  173. agno/memory/strategies/summarize.py +196 -0
  174. agno/memory/strategies/types.py +37 -0
  175. agno/models/aimlapi/__init__.py +5 -0
  176. agno/models/aimlapi/aimlapi.py +62 -0
  177. agno/models/anthropic/__init__.py +4 -0
  178. agno/models/anthropic/claude.py +960 -496
  179. agno/models/aws/__init__.py +15 -0
  180. agno/models/aws/bedrock.py +686 -451
  181. agno/models/aws/claude.py +190 -183
  182. agno/models/azure/__init__.py +18 -1
  183. agno/models/azure/ai_foundry.py +489 -0
  184. agno/models/azure/openai_chat.py +89 -40
  185. agno/models/base.py +2477 -550
  186. agno/models/cerebras/__init__.py +12 -0
  187. agno/models/cerebras/cerebras.py +565 -0
  188. agno/models/cerebras/cerebras_openai.py +131 -0
  189. agno/models/cohere/__init__.py +4 -0
  190. agno/models/cohere/chat.py +306 -492
  191. agno/models/cometapi/__init__.py +5 -0
  192. agno/models/cometapi/cometapi.py +74 -0
  193. agno/models/dashscope/__init__.py +5 -0
  194. agno/models/dashscope/dashscope.py +90 -0
  195. agno/models/deepinfra/__init__.py +5 -0
  196. agno/models/deepinfra/deepinfra.py +45 -0
  197. agno/models/deepseek/__init__.py +4 -0
  198. agno/models/deepseek/deepseek.py +110 -9
  199. agno/models/fireworks/__init__.py +4 -0
  200. agno/models/fireworks/fireworks.py +19 -22
  201. agno/models/google/__init__.py +3 -7
  202. agno/models/google/gemini.py +1717 -662
  203. agno/models/google/utils.py +22 -0
  204. agno/models/groq/__init__.py +4 -0
  205. agno/models/groq/groq.py +391 -666
  206. agno/models/huggingface/__init__.py +4 -0
  207. agno/models/huggingface/huggingface.py +266 -538
  208. agno/models/ibm/__init__.py +5 -0
  209. agno/models/ibm/watsonx.py +432 -0
  210. agno/models/internlm/__init__.py +3 -0
  211. agno/models/internlm/internlm.py +20 -3
  212. agno/models/langdb/__init__.py +1 -0
  213. agno/models/langdb/langdb.py +60 -0
  214. agno/models/litellm/__init__.py +14 -0
  215. agno/models/litellm/chat.py +503 -0
  216. agno/models/litellm/litellm_openai.py +42 -0
  217. agno/models/llama_cpp/__init__.py +5 -0
  218. agno/models/llama_cpp/llama_cpp.py +22 -0
  219. agno/models/lmstudio/__init__.py +5 -0
  220. agno/models/lmstudio/lmstudio.py +25 -0
  221. agno/models/message.py +361 -39
  222. agno/models/meta/__init__.py +12 -0
  223. agno/models/meta/llama.py +502 -0
  224. agno/models/meta/llama_openai.py +79 -0
  225. agno/models/metrics.py +120 -0
  226. agno/models/mistral/__init__.py +4 -0
  227. agno/models/mistral/mistral.py +293 -393
  228. agno/models/nebius/__init__.py +3 -0
  229. agno/models/nebius/nebius.py +53 -0
  230. agno/models/nexus/__init__.py +3 -0
  231. agno/models/nexus/nexus.py +22 -0
  232. agno/models/nvidia/__init__.py +4 -0
  233. agno/models/nvidia/nvidia.py +22 -3
  234. agno/models/ollama/__init__.py +4 -2
  235. agno/models/ollama/chat.py +257 -492
  236. agno/models/openai/__init__.py +7 -0
  237. agno/models/openai/chat.py +725 -770
  238. agno/models/openai/like.py +16 -2
  239. agno/models/openai/responses.py +1121 -0
  240. agno/models/openrouter/__init__.py +4 -0
  241. agno/models/openrouter/openrouter.py +62 -5
  242. agno/models/perplexity/__init__.py +5 -0
  243. agno/models/perplexity/perplexity.py +203 -0
  244. agno/models/portkey/__init__.py +3 -0
  245. agno/models/portkey/portkey.py +82 -0
  246. agno/models/requesty/__init__.py +5 -0
  247. agno/models/requesty/requesty.py +69 -0
  248. agno/models/response.py +177 -7
  249. agno/models/sambanova/__init__.py +4 -0
  250. agno/models/sambanova/sambanova.py +23 -4
  251. agno/models/siliconflow/__init__.py +5 -0
  252. agno/models/siliconflow/siliconflow.py +42 -0
  253. agno/models/together/__init__.py +4 -0
  254. agno/models/together/together.py +21 -164
  255. agno/models/utils.py +266 -0
  256. agno/models/vercel/__init__.py +3 -0
  257. agno/models/vercel/v0.py +43 -0
  258. agno/models/vertexai/__init__.py +0 -1
  259. agno/models/vertexai/claude.py +190 -0
  260. agno/models/vllm/__init__.py +3 -0
  261. agno/models/vllm/vllm.py +83 -0
  262. agno/models/xai/__init__.py +2 -0
  263. agno/models/xai/xai.py +111 -7
  264. agno/os/__init__.py +3 -0
  265. agno/os/app.py +1027 -0
  266. agno/os/auth.py +244 -0
  267. agno/os/config.py +126 -0
  268. agno/os/interfaces/__init__.py +1 -0
  269. agno/os/interfaces/a2a/__init__.py +3 -0
  270. agno/os/interfaces/a2a/a2a.py +42 -0
  271. agno/os/interfaces/a2a/router.py +249 -0
  272. agno/os/interfaces/a2a/utils.py +924 -0
  273. agno/os/interfaces/agui/__init__.py +3 -0
  274. agno/os/interfaces/agui/agui.py +47 -0
  275. agno/os/interfaces/agui/router.py +147 -0
  276. agno/os/interfaces/agui/utils.py +574 -0
  277. agno/os/interfaces/base.py +25 -0
  278. agno/os/interfaces/slack/__init__.py +3 -0
  279. agno/os/interfaces/slack/router.py +148 -0
  280. agno/os/interfaces/slack/security.py +30 -0
  281. agno/os/interfaces/slack/slack.py +47 -0
  282. agno/os/interfaces/whatsapp/__init__.py +3 -0
  283. agno/os/interfaces/whatsapp/router.py +210 -0
  284. agno/os/interfaces/whatsapp/security.py +55 -0
  285. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  286. agno/os/mcp.py +293 -0
  287. agno/os/middleware/__init__.py +9 -0
  288. agno/os/middleware/jwt.py +797 -0
  289. agno/os/router.py +258 -0
  290. agno/os/routers/__init__.py +3 -0
  291. agno/os/routers/agents/__init__.py +3 -0
  292. agno/os/routers/agents/router.py +599 -0
  293. agno/os/routers/agents/schema.py +261 -0
  294. agno/os/routers/evals/__init__.py +3 -0
  295. agno/os/routers/evals/evals.py +450 -0
  296. agno/os/routers/evals/schemas.py +174 -0
  297. agno/os/routers/evals/utils.py +231 -0
  298. agno/os/routers/health.py +31 -0
  299. agno/os/routers/home.py +52 -0
  300. agno/os/routers/knowledge/__init__.py +3 -0
  301. agno/os/routers/knowledge/knowledge.py +1008 -0
  302. agno/os/routers/knowledge/schemas.py +178 -0
  303. agno/os/routers/memory/__init__.py +3 -0
  304. agno/os/routers/memory/memory.py +661 -0
  305. agno/os/routers/memory/schemas.py +88 -0
  306. agno/os/routers/metrics/__init__.py +3 -0
  307. agno/os/routers/metrics/metrics.py +190 -0
  308. agno/os/routers/metrics/schemas.py +47 -0
  309. agno/os/routers/session/__init__.py +3 -0
  310. agno/os/routers/session/session.py +997 -0
  311. agno/os/routers/teams/__init__.py +3 -0
  312. agno/os/routers/teams/router.py +512 -0
  313. agno/os/routers/teams/schema.py +257 -0
  314. agno/os/routers/traces/__init__.py +3 -0
  315. agno/os/routers/traces/schemas.py +414 -0
  316. agno/os/routers/traces/traces.py +499 -0
  317. agno/os/routers/workflows/__init__.py +3 -0
  318. agno/os/routers/workflows/router.py +624 -0
  319. agno/os/routers/workflows/schema.py +75 -0
  320. agno/os/schema.py +534 -0
  321. agno/os/scopes.py +469 -0
  322. agno/{playground → os}/settings.py +7 -15
  323. agno/os/utils.py +973 -0
  324. agno/reasoning/anthropic.py +80 -0
  325. agno/reasoning/azure_ai_foundry.py +67 -0
  326. agno/reasoning/deepseek.py +63 -0
  327. agno/reasoning/default.py +97 -0
  328. agno/reasoning/gemini.py +73 -0
  329. agno/reasoning/groq.py +71 -0
  330. agno/reasoning/helpers.py +24 -1
  331. agno/reasoning/ollama.py +67 -0
  332. agno/reasoning/openai.py +86 -0
  333. agno/reasoning/step.py +2 -1
  334. agno/reasoning/vertexai.py +76 -0
  335. agno/run/__init__.py +6 -0
  336. agno/run/agent.py +822 -0
  337. agno/run/base.py +247 -0
  338. agno/run/cancel.py +81 -0
  339. agno/run/requirement.py +181 -0
  340. agno/run/team.py +767 -0
  341. agno/run/workflow.py +708 -0
  342. agno/session/__init__.py +10 -0
  343. agno/session/agent.py +260 -0
  344. agno/session/summary.py +265 -0
  345. agno/session/team.py +342 -0
  346. agno/session/workflow.py +501 -0
  347. agno/table.py +10 -0
  348. agno/team/__init__.py +37 -0
  349. agno/team/team.py +9536 -0
  350. agno/tools/__init__.py +7 -0
  351. agno/tools/agentql.py +120 -0
  352. agno/tools/airflow.py +22 -12
  353. agno/tools/api.py +122 -0
  354. agno/tools/apify.py +276 -83
  355. agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
  356. agno/tools/aws_lambda.py +28 -7
  357. agno/tools/aws_ses.py +66 -0
  358. agno/tools/baidusearch.py +11 -4
  359. agno/tools/bitbucket.py +292 -0
  360. agno/tools/brandfetch.py +213 -0
  361. agno/tools/bravesearch.py +106 -0
  362. agno/tools/brightdata.py +367 -0
  363. agno/tools/browserbase.py +209 -0
  364. agno/tools/calcom.py +32 -23
  365. agno/tools/calculator.py +24 -37
  366. agno/tools/cartesia.py +187 -0
  367. agno/tools/{clickup_tool.py → clickup.py} +17 -28
  368. agno/tools/confluence.py +91 -26
  369. agno/tools/crawl4ai.py +139 -43
  370. agno/tools/csv_toolkit.py +28 -22
  371. agno/tools/dalle.py +36 -22
  372. agno/tools/daytona.py +475 -0
  373. agno/tools/decorator.py +169 -14
  374. agno/tools/desi_vocal.py +23 -11
  375. agno/tools/discord.py +32 -29
  376. agno/tools/docker.py +716 -0
  377. agno/tools/duckdb.py +76 -81
  378. agno/tools/duckduckgo.py +43 -40
  379. agno/tools/e2b.py +703 -0
  380. agno/tools/eleven_labs.py +65 -54
  381. agno/tools/email.py +13 -5
  382. agno/tools/evm.py +129 -0
  383. agno/tools/exa.py +324 -42
  384. agno/tools/fal.py +39 -35
  385. agno/tools/file.py +196 -30
  386. agno/tools/file_generation.py +356 -0
  387. agno/tools/financial_datasets.py +288 -0
  388. agno/tools/firecrawl.py +108 -33
  389. agno/tools/function.py +960 -122
  390. agno/tools/giphy.py +34 -12
  391. agno/tools/github.py +1294 -97
  392. agno/tools/gmail.py +922 -0
  393. agno/tools/google_bigquery.py +117 -0
  394. agno/tools/google_drive.py +271 -0
  395. agno/tools/google_maps.py +253 -0
  396. agno/tools/googlecalendar.py +607 -107
  397. agno/tools/googlesheets.py +377 -0
  398. agno/tools/hackernews.py +20 -12
  399. agno/tools/jina.py +24 -14
  400. agno/tools/jira.py +48 -19
  401. agno/tools/knowledge.py +218 -0
  402. agno/tools/linear.py +82 -43
  403. agno/tools/linkup.py +58 -0
  404. agno/tools/local_file_system.py +15 -7
  405. agno/tools/lumalab.py +41 -26
  406. agno/tools/mcp/__init__.py +10 -0
  407. agno/tools/mcp/mcp.py +331 -0
  408. agno/tools/mcp/multi_mcp.py +347 -0
  409. agno/tools/mcp/params.py +24 -0
  410. agno/tools/mcp_toolbox.py +284 -0
  411. agno/tools/mem0.py +193 -0
  412. agno/tools/memory.py +419 -0
  413. agno/tools/mlx_transcribe.py +11 -9
  414. agno/tools/models/azure_openai.py +190 -0
  415. agno/tools/models/gemini.py +203 -0
  416. agno/tools/models/groq.py +158 -0
  417. agno/tools/models/morph.py +186 -0
  418. agno/tools/models/nebius.py +124 -0
  419. agno/tools/models_labs.py +163 -82
  420. agno/tools/moviepy_video.py +18 -13
  421. agno/tools/nano_banana.py +151 -0
  422. agno/tools/neo4j.py +134 -0
  423. agno/tools/newspaper.py +15 -4
  424. agno/tools/newspaper4k.py +19 -6
  425. agno/tools/notion.py +204 -0
  426. agno/tools/openai.py +181 -17
  427. agno/tools/openbb.py +27 -20
  428. agno/tools/opencv.py +321 -0
  429. agno/tools/openweather.py +233 -0
  430. agno/tools/oxylabs.py +385 -0
  431. agno/tools/pandas.py +25 -15
  432. agno/tools/parallel.py +314 -0
  433. agno/tools/postgres.py +238 -185
  434. agno/tools/pubmed.py +125 -13
  435. agno/tools/python.py +48 -35
  436. agno/tools/reasoning.py +283 -0
  437. agno/tools/reddit.py +207 -29
  438. agno/tools/redshift.py +406 -0
  439. agno/tools/replicate.py +69 -26
  440. agno/tools/resend.py +11 -6
  441. agno/tools/scrapegraph.py +179 -19
  442. agno/tools/searxng.py +23 -31
  443. agno/tools/serpapi.py +15 -10
  444. agno/tools/serper.py +255 -0
  445. agno/tools/shell.py +23 -12
  446. agno/tools/shopify.py +1519 -0
  447. agno/tools/slack.py +56 -14
  448. agno/tools/sleep.py +8 -6
  449. agno/tools/spider.py +35 -11
  450. agno/tools/spotify.py +919 -0
  451. agno/tools/sql.py +34 -19
  452. agno/tools/tavily.py +158 -8
  453. agno/tools/telegram.py +18 -8
  454. agno/tools/todoist.py +218 -0
  455. agno/tools/toolkit.py +134 -9
  456. agno/tools/trafilatura.py +388 -0
  457. agno/tools/trello.py +25 -28
  458. agno/tools/twilio.py +18 -9
  459. agno/tools/user_control_flow.py +78 -0
  460. agno/tools/valyu.py +228 -0
  461. agno/tools/visualization.py +467 -0
  462. agno/tools/webbrowser.py +28 -0
  463. agno/tools/webex.py +76 -0
  464. agno/tools/website.py +23 -19
  465. agno/tools/webtools.py +45 -0
  466. agno/tools/whatsapp.py +286 -0
  467. agno/tools/wikipedia.py +28 -19
  468. agno/tools/workflow.py +285 -0
  469. agno/tools/{twitter.py → x.py} +142 -46
  470. agno/tools/yfinance.py +41 -39
  471. agno/tools/youtube.py +34 -17
  472. agno/tools/zendesk.py +15 -5
  473. agno/tools/zep.py +454 -0
  474. agno/tools/zoom.py +86 -37
  475. agno/tracing/__init__.py +12 -0
  476. agno/tracing/exporter.py +157 -0
  477. agno/tracing/schemas.py +276 -0
  478. agno/tracing/setup.py +111 -0
  479. agno/utils/agent.py +938 -0
  480. agno/utils/audio.py +37 -1
  481. agno/utils/certs.py +27 -0
  482. agno/utils/code_execution.py +11 -0
  483. agno/utils/common.py +103 -20
  484. agno/utils/cryptography.py +22 -0
  485. agno/utils/dttm.py +33 -0
  486. agno/utils/events.py +700 -0
  487. agno/utils/functions.py +107 -37
  488. agno/utils/gemini.py +426 -0
  489. agno/utils/hooks.py +171 -0
  490. agno/utils/http.py +185 -0
  491. agno/utils/json_schema.py +159 -37
  492. agno/utils/knowledge.py +36 -0
  493. agno/utils/location.py +19 -0
  494. agno/utils/log.py +221 -8
  495. agno/utils/mcp.py +214 -0
  496. agno/utils/media.py +335 -14
  497. agno/utils/merge_dict.py +22 -1
  498. agno/utils/message.py +77 -2
  499. agno/utils/models/ai_foundry.py +50 -0
  500. agno/utils/models/claude.py +373 -0
  501. agno/utils/models/cohere.py +94 -0
  502. agno/utils/models/llama.py +85 -0
  503. agno/utils/models/mistral.py +100 -0
  504. agno/utils/models/openai_responses.py +140 -0
  505. agno/utils/models/schema_utils.py +153 -0
  506. agno/utils/models/watsonx.py +41 -0
  507. agno/utils/openai.py +257 -0
  508. agno/utils/pickle.py +1 -1
  509. agno/utils/pprint.py +124 -8
  510. agno/utils/print_response/agent.py +930 -0
  511. agno/utils/print_response/team.py +1914 -0
  512. agno/utils/print_response/workflow.py +1668 -0
  513. agno/utils/prompts.py +111 -0
  514. agno/utils/reasoning.py +108 -0
  515. agno/utils/response.py +163 -0
  516. agno/utils/serialize.py +32 -0
  517. agno/utils/shell.py +4 -4
  518. agno/utils/streamlit.py +487 -0
  519. agno/utils/string.py +204 -51
  520. agno/utils/team.py +139 -0
  521. agno/utils/timer.py +9 -2
  522. agno/utils/tokens.py +657 -0
  523. agno/utils/tools.py +19 -1
  524. agno/utils/whatsapp.py +305 -0
  525. agno/utils/yaml_io.py +3 -3
  526. agno/vectordb/__init__.py +2 -0
  527. agno/vectordb/base.py +87 -9
  528. agno/vectordb/cassandra/__init__.py +5 -1
  529. agno/vectordb/cassandra/cassandra.py +383 -27
  530. agno/vectordb/chroma/__init__.py +4 -0
  531. agno/vectordb/chroma/chromadb.py +748 -83
  532. agno/vectordb/clickhouse/__init__.py +7 -1
  533. agno/vectordb/clickhouse/clickhousedb.py +554 -53
  534. agno/vectordb/couchbase/__init__.py +3 -0
  535. agno/vectordb/couchbase/couchbase.py +1446 -0
  536. agno/vectordb/lancedb/__init__.py +5 -0
  537. agno/vectordb/lancedb/lance_db.py +730 -98
  538. agno/vectordb/langchaindb/__init__.py +5 -0
  539. agno/vectordb/langchaindb/langchaindb.py +163 -0
  540. agno/vectordb/lightrag/__init__.py +5 -0
  541. agno/vectordb/lightrag/lightrag.py +388 -0
  542. agno/vectordb/llamaindex/__init__.py +3 -0
  543. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  544. agno/vectordb/milvus/__init__.py +3 -0
  545. agno/vectordb/milvus/milvus.py +966 -78
  546. agno/vectordb/mongodb/__init__.py +9 -1
  547. agno/vectordb/mongodb/mongodb.py +1175 -172
  548. agno/vectordb/pgvector/__init__.py +8 -0
  549. agno/vectordb/pgvector/pgvector.py +599 -115
  550. agno/vectordb/pineconedb/__init__.py +5 -1
  551. agno/vectordb/pineconedb/pineconedb.py +406 -43
  552. agno/vectordb/qdrant/__init__.py +4 -0
  553. agno/vectordb/qdrant/qdrant.py +914 -61
  554. agno/vectordb/redis/__init__.py +9 -0
  555. agno/vectordb/redis/redisdb.py +682 -0
  556. agno/vectordb/singlestore/__init__.py +8 -1
  557. agno/vectordb/singlestore/singlestore.py +771 -0
  558. agno/vectordb/surrealdb/__init__.py +3 -0
  559. agno/vectordb/surrealdb/surrealdb.py +663 -0
  560. agno/vectordb/upstashdb/__init__.py +5 -0
  561. agno/vectordb/upstashdb/upstashdb.py +718 -0
  562. agno/vectordb/weaviate/__init__.py +8 -0
  563. agno/vectordb/weaviate/index.py +15 -0
  564. agno/vectordb/weaviate/weaviate.py +1009 -0
  565. agno/workflow/__init__.py +23 -1
  566. agno/workflow/agent.py +299 -0
  567. agno/workflow/condition.py +759 -0
  568. agno/workflow/loop.py +756 -0
  569. agno/workflow/parallel.py +853 -0
  570. agno/workflow/router.py +723 -0
  571. agno/workflow/step.py +1564 -0
  572. agno/workflow/steps.py +613 -0
  573. agno/workflow/types.py +556 -0
  574. agno/workflow/workflow.py +4327 -514
  575. agno-2.3.13.dist-info/METADATA +639 -0
  576. agno-2.3.13.dist-info/RECORD +613 -0
  577. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
  578. agno-2.3.13.dist-info/licenses/LICENSE +201 -0
  579. agno/api/playground.py +0 -91
  580. agno/api/schemas/playground.py +0 -22
  581. agno/api/schemas/user.py +0 -22
  582. agno/api/schemas/workspace.py +0 -46
  583. agno/api/user.py +0 -160
  584. agno/api/workspace.py +0 -151
  585. agno/cli/auth_server.py +0 -118
  586. agno/cli/config.py +0 -275
  587. agno/cli/console.py +0 -88
  588. agno/cli/credentials.py +0 -23
  589. agno/cli/entrypoint.py +0 -571
  590. agno/cli/operator.py +0 -355
  591. agno/cli/settings.py +0 -85
  592. agno/cli/ws/ws_cli.py +0 -817
  593. agno/constants.py +0 -13
  594. agno/document/__init__.py +0 -1
  595. agno/document/chunking/semantic.py +0 -47
  596. agno/document/chunking/strategy.py +0 -31
  597. agno/document/reader/__init__.py +0 -1
  598. agno/document/reader/arxiv_reader.py +0 -41
  599. agno/document/reader/base.py +0 -22
  600. agno/document/reader/csv_reader.py +0 -84
  601. agno/document/reader/docx_reader.py +0 -46
  602. agno/document/reader/firecrawl_reader.py +0 -99
  603. agno/document/reader/json_reader.py +0 -43
  604. agno/document/reader/pdf_reader.py +0 -219
  605. agno/document/reader/s3/pdf_reader.py +0 -46
  606. agno/document/reader/s3/text_reader.py +0 -51
  607. agno/document/reader/text_reader.py +0 -41
  608. agno/document/reader/website_reader.py +0 -175
  609. agno/document/reader/youtube_reader.py +0 -50
  610. agno/embedder/__init__.py +0 -1
  611. agno/embedder/azure_openai.py +0 -86
  612. agno/embedder/cohere.py +0 -72
  613. agno/embedder/fastembed.py +0 -37
  614. agno/embedder/google.py +0 -73
  615. agno/embedder/huggingface.py +0 -54
  616. agno/embedder/mistral.py +0 -80
  617. agno/embedder/ollama.py +0 -57
  618. agno/embedder/openai.py +0 -74
  619. agno/embedder/sentence_transformer.py +0 -38
  620. agno/embedder/voyageai.py +0 -64
  621. agno/eval/perf.py +0 -201
  622. agno/file/__init__.py +0 -1
  623. agno/file/file.py +0 -16
  624. agno/file/local/csv.py +0 -32
  625. agno/file/local/txt.py +0 -19
  626. agno/infra/app.py +0 -240
  627. agno/infra/base.py +0 -144
  628. agno/infra/context.py +0 -20
  629. agno/infra/db_app.py +0 -52
  630. agno/infra/resource.py +0 -205
  631. agno/infra/resources.py +0 -55
  632. agno/knowledge/agent.py +0 -230
  633. agno/knowledge/arxiv.py +0 -22
  634. agno/knowledge/combined.py +0 -22
  635. agno/knowledge/csv.py +0 -28
  636. agno/knowledge/csv_url.py +0 -19
  637. agno/knowledge/document.py +0 -20
  638. agno/knowledge/docx.py +0 -30
  639. agno/knowledge/json.py +0 -28
  640. agno/knowledge/langchain.py +0 -71
  641. agno/knowledge/llamaindex.py +0 -66
  642. agno/knowledge/pdf.py +0 -28
  643. agno/knowledge/pdf_url.py +0 -26
  644. agno/knowledge/s3/base.py +0 -60
  645. agno/knowledge/s3/pdf.py +0 -21
  646. agno/knowledge/s3/text.py +0 -23
  647. agno/knowledge/text.py +0 -30
  648. agno/knowledge/website.py +0 -88
  649. agno/knowledge/wikipedia.py +0 -31
  650. agno/knowledge/youtube.py +0 -22
  651. agno/memory/agent.py +0 -392
  652. agno/memory/classifier.py +0 -104
  653. agno/memory/db/__init__.py +0 -1
  654. agno/memory/db/base.py +0 -42
  655. agno/memory/db/mongodb.py +0 -189
  656. agno/memory/db/postgres.py +0 -203
  657. agno/memory/db/sqlite.py +0 -193
  658. agno/memory/memory.py +0 -15
  659. agno/memory/row.py +0 -36
  660. agno/memory/summarizer.py +0 -192
  661. agno/memory/summary.py +0 -19
  662. agno/memory/workflow.py +0 -38
  663. agno/models/google/gemini_openai.py +0 -26
  664. agno/models/ollama/hermes.py +0 -221
  665. agno/models/ollama/tools.py +0 -362
  666. agno/models/vertexai/gemini.py +0 -595
  667. agno/playground/__init__.py +0 -3
  668. agno/playground/async_router.py +0 -421
  669. agno/playground/deploy.py +0 -249
  670. agno/playground/operator.py +0 -92
  671. agno/playground/playground.py +0 -91
  672. agno/playground/schemas.py +0 -76
  673. agno/playground/serve.py +0 -55
  674. agno/playground/sync_router.py +0 -405
  675. agno/reasoning/agent.py +0 -68
  676. agno/run/response.py +0 -112
  677. agno/storage/agent/__init__.py +0 -0
  678. agno/storage/agent/base.py +0 -38
  679. agno/storage/agent/dynamodb.py +0 -350
  680. agno/storage/agent/json.py +0 -92
  681. agno/storage/agent/mongodb.py +0 -228
  682. agno/storage/agent/postgres.py +0 -367
  683. agno/storage/agent/session.py +0 -79
  684. agno/storage/agent/singlestore.py +0 -303
  685. agno/storage/agent/sqlite.py +0 -357
  686. agno/storage/agent/yaml.py +0 -93
  687. agno/storage/workflow/__init__.py +0 -0
  688. agno/storage/workflow/base.py +0 -40
  689. agno/storage/workflow/mongodb.py +0 -233
  690. agno/storage/workflow/postgres.py +0 -366
  691. agno/storage/workflow/session.py +0 -60
  692. agno/storage/workflow/sqlite.py +0 -359
  693. agno/tools/googlesearch.py +0 -88
  694. agno/utils/defaults.py +0 -57
  695. agno/utils/filesystem.py +0 -39
  696. agno/utils/git.py +0 -52
  697. agno/utils/json_io.py +0 -30
  698. agno/utils/load_env.py +0 -19
  699. agno/utils/py_io.py +0 -19
  700. agno/utils/pyproject.py +0 -18
  701. agno/utils/resource_filter.py +0 -31
  702. agno/vectordb/singlestore/s2vectordb.py +0 -390
  703. agno/vectordb/singlestore/s2vectordb2.py +0 -355
  704. agno/workspace/__init__.py +0 -0
  705. agno/workspace/config.py +0 -325
  706. agno/workspace/enums.py +0 -6
  707. agno/workspace/helpers.py +0 -48
  708. agno/workspace/operator.py +0 -758
  709. agno/workspace/settings.py +0 -63
  710. agno-0.1.2.dist-info/LICENSE +0 -375
  711. agno-0.1.2.dist-info/METADATA +0 -502
  712. agno-0.1.2.dist-info/RECORD +0 -352
  713. agno-0.1.2.dist-info/entry_points.txt +0 -3
  714. /agno/{cli → db/migrations}/__init__.py +0 -0
  715. /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
  716. /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
  717. /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
  718. /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
  719. /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
  720. /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
  721. /agno/{reranker → utils/models}/__init__.py +0 -0
  722. /agno/{storage → utils/print_response}/__init__.py +0 -0
  723. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
agno/tools/exa.py CHANGED
@@ -1,24 +1,64 @@
1
1
  import json
2
+ from concurrent.futures import ThreadPoolExecutor, TimeoutError
2
3
  from os import getenv
3
- from typing import Any, Dict, List, Optional
4
+ from typing import Any, Dict, List, Literal, Optional
4
5
 
5
6
  from agno.tools import Toolkit
6
- from agno.utils.log import logger
7
+ from agno.utils.log import log_debug, log_info, logger
7
8
 
8
9
  try:
9
10
  from exa_py import Exa
11
+ from exa_py.api import SearchResponse
10
12
  except ImportError:
11
13
  raise ImportError("`exa_py` not installed. Please install using `pip install exa_py`")
12
14
 
13
15
 
14
16
  class ExaTools(Toolkit):
17
+ """
18
+ ExaTools is a toolkit for interfacing with the Exa web search engine, providing
19
+ functionalities to perform categorized searches and retrieve structured results.
20
+
21
+ Args:
22
+ enable_search (bool): Enable search functionality. Default is True.
23
+ enable_get_contents (bool): Enable get contents functionality. Default is True.
24
+ enable_find_similar (bool): Enable find similar functionality. Default is True.
25
+ enable_answer (bool): Enable answer generation. Default is True.
26
+ enable_research (bool): Enable research tool functionality. Default is False.
27
+ all (bool): Enable all tools. Overrides individual flags when True. Default is False.
28
+ text (bool): Retrieve text content from results. Default is True.
29
+ text_length_limit (int): Max length of text content per result. Default is 1000.
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
+ api_key (Optional[str]): Exa API key. Retrieved from `EXA_API_KEY` env variable if not provided.
32
+ num_results (Optional[int]): Default number of search results. Overrides individual searches if set.
33
+ start_crawl_date (Optional[str]): Include results crawled on/after this date (`YYYY-MM-DD`).
34
+ end_crawl_date (Optional[str]): Include results crawled on/before this date (`YYYY-MM-DD`).
35
+ start_published_date (Optional[str]): Include results published on/after this date (`YYYY-MM-DD`).
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. Deprecated since it was removed in the Exa API. It will be removed from Agno in a future release.
38
+ type (Optional[str]): Specify content type (e.g., article, blog, video).
39
+ category (Optional[str]): Filter results by category. Options are "company", "research paper", "news", "pdf", "github", "tweet", "personal site", "linkedin profile", "financial report".
40
+ include_domains (Optional[List[str]]): Restrict results to these domains.
41
+ exclude_domains (Optional[List[str]]): Exclude results from these domains.
42
+ show_results (bool): Log search results for debugging. Default is False.
43
+ model (Optional[str]): The search model to use. Options are 'exa' or 'exa-pro'.
44
+ timeout (int): Maximum time in seconds to wait for API responses. Default is 30 seconds.
45
+ """
46
+
15
47
  def __init__(
16
48
  self,
49
+ enable_search: bool = True,
50
+ enable_get_contents: bool = True,
51
+ enable_find_similar: bool = True,
52
+ enable_answer: bool = True,
53
+ enable_research: bool = False,
54
+ all: bool = False,
17
55
  text: bool = True,
18
56
  text_length_limit: int = 1000,
19
- highlights: bool = True,
57
+ highlights: Optional[bool] = None, # Deprecated
58
+ summary: bool = False,
20
59
  api_key: Optional[str] = None,
21
60
  num_results: Optional[int] = None,
61
+ livecrawl: str = "always",
22
62
  start_crawl_date: Optional[str] = None,
23
63
  end_crawl_date: Optional[str] = None,
24
64
  start_published_date: Optional[str] = None,
@@ -27,88 +67,330 @@ class ExaTools(Toolkit):
27
67
  type: Optional[str] = None,
28
68
  category: Optional[str] = None,
29
69
  include_domains: Optional[List[str]] = None,
70
+ exclude_domains: Optional[List[str]] = None,
30
71
  show_results: bool = False,
72
+ model: Optional[str] = None,
73
+ timeout: int = 30,
74
+ research_model: Literal["exa-research", "exa-research-pro"] = "exa-research",
75
+ **kwargs,
31
76
  ):
32
- super().__init__(name="exa")
33
-
34
77
  self.api_key = api_key or getenv("EXA_API_KEY")
35
78
  if not self.api_key:
36
79
  logger.error("EXA_API_KEY not set. Please set the EXA_API_KEY environment variable.")
37
80
 
81
+ self.exa = Exa(self.api_key)
38
82
  self.show_results = show_results
83
+ self.timeout = timeout
39
84
 
40
85
  self.text: bool = text
41
86
  self.text_length_limit: int = text_length_limit
42
- 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
+
105
+ self.summary: bool = summary
43
106
  self.num_results: Optional[int] = num_results
107
+ self.livecrawl: str = livecrawl
44
108
  self.start_crawl_date: Optional[str] = start_crawl_date
45
109
  self.end_crawl_date: Optional[str] = end_crawl_date
46
110
  self.start_published_date: Optional[str] = start_published_date
47
111
  self.end_published_date: Optional[str] = end_published_date
48
- self.use_autoprompt: Optional[bool] = use_autoprompt
49
112
  self.type: Optional[str] = type
50
- self.include_domains: Optional[List[str]] = include_domains
51
113
  self.category: Optional[str] = category
114
+ self.include_domains: Optional[List[str]] = include_domains
115
+ self.exclude_domains: Optional[List[str]] = exclude_domains
116
+ self.model: Optional[str] = model
117
+ self.research_model: Literal["exa-research", "exa-research-pro"] = research_model
118
+
119
+ tools: List[Any] = []
120
+ if all or enable_search:
121
+ tools.append(self.search_exa)
122
+ if all or enable_get_contents:
123
+ tools.append(self.get_contents)
124
+ if all or enable_find_similar:
125
+ tools.append(self.find_similar)
126
+ if all or enable_answer:
127
+ tools.append(self.exa_answer)
128
+ if all or enable_research:
129
+ tools.append(self.research)
130
+
131
+ super().__init__(name="exa", tools=tools, **kwargs)
132
+
133
+ def _execute_with_timeout(self, func, *args, **kwargs):
134
+ """Execute a function with a timeout using a temporary ThreadPoolExecutor."""
135
+ with ThreadPoolExecutor(max_workers=1) as executor:
136
+ future = executor.submit(func, *args, **kwargs)
137
+ try:
138
+ return future.result(timeout=self.timeout)
139
+ except TimeoutError:
140
+ raise TimeoutError(f"Operation timed out after {self.timeout} seconds")
141
+ except Exception as e:
142
+ raise e
52
143
 
53
- self.register(self.search_exa)
144
+ def _parse_results(self, exa_results: SearchResponse) -> str:
145
+ exa_results_parsed = []
146
+ for result in exa_results.results:
147
+ result_dict = {"url": result.url}
148
+ if result.title:
149
+ result_dict["title"] = result.title
150
+ if result.author and result.author != "":
151
+ result_dict["author"] = result.author
152
+ if result.published_date:
153
+ result_dict["published_date"] = result.published_date
154
+ if result.text:
155
+ _text = result.text
156
+ if self.text_length_limit:
157
+ _text = _text[: self.text_length_limit]
158
+ result_dict["text"] = _text
159
+ exa_results_parsed.append(result_dict)
160
+ return json.dumps(exa_results_parsed, indent=4, ensure_ascii=False)
54
161
 
55
- def search_exa(self, query: str, num_results: int = 5) -> str:
162
+ def search_exa(self, query: str, num_results: int = 5, category: Optional[str] = None) -> str:
56
163
  """Use this function to search Exa (a web search engine) for a query.
57
164
 
58
165
  Args:
59
166
  query (str): The query to search for.
60
167
  num_results (int): Number of results to return. Defaults to 5.
168
+ category (Optional[str]): The category to filter search results.
169
+ Options are "company", "research paper", "news", "pdf", "github",
170
+ "tweet", "personal site", "linkedin profile", "financial report".
61
171
 
62
172
  Returns:
63
173
  str: The search results in JSON format.
64
174
  """
65
- if not self.api_key:
66
- return "Please set the EXA_API_KEY"
67
-
68
175
  try:
69
- exa = Exa(self.api_key)
70
- logger.info(f"Searching exa for: {query}")
176
+ if self.show_results:
177
+ log_info(f"Searching exa for: {query}")
71
178
  search_kwargs: Dict[str, Any] = {
72
179
  "text": self.text,
73
- "highlights": self.highlights,
180
+ "summary": self.summary,
74
181
  "num_results": self.num_results or num_results,
75
182
  "start_crawl_date": self.start_crawl_date,
76
183
  "end_crawl_date": self.end_crawl_date,
77
184
  "start_published_date": self.start_published_date,
78
185
  "end_published_date": self.end_published_date,
79
- "use_autoprompt": self.use_autoprompt,
80
186
  "type": self.type,
81
- "category": self.category,
187
+ "category": self.category or category, # Prefer a user-set category
82
188
  "include_domains": self.include_domains,
189
+ "exclude_domains": self.exclude_domains,
83
190
  }
84
191
  # Clean up the kwargs
85
192
  search_kwargs = {k: v for k, v in search_kwargs.items() if v is not None}
86
- exa_results = exa.search_and_contents(query, **search_kwargs)
87
- exa_results_parsed = []
88
- for result in exa_results.results:
89
- result_dict = {"url": result.url}
90
- if result.title:
91
- result_dict["title"] = result.title
92
- if result.author and result.author != "":
93
- result_dict["author"] = result.author
94
- if result.published_date:
95
- result_dict["published_date"] = result.published_date
96
- if result.text:
97
- _text = result.text
98
- if self.text_length_limit:
99
- _text = _text[: self.text_length_limit]
100
- result_dict["text"] = _text
101
- if self.highlights:
102
- try:
103
- if result.highlights: # type: ignore
104
- result_dict["highlights"] = result.highlights # type: ignore
105
- except Exception as e:
106
- logger.debug(f"Failed to get highlights {e}")
107
- exa_results_parsed.append(result_dict)
108
- parsed_results = json.dumps(exa_results_parsed, indent=4)
193
+
194
+ # Execute search with timeout
195
+ exa_results = self._execute_with_timeout(self.exa.search_and_contents, query, **search_kwargs)
196
+
197
+ parsed_results = self._parse_results(exa_results)
198
+ # Extract search results
109
199
  if self.show_results:
110
- logger.info(parsed_results)
200
+ log_info(parsed_results)
111
201
  return parsed_results
202
+ except TimeoutError as e:
203
+ logger.error(f"Search timed out after {self.timeout} seconds")
204
+ return f"Error: {str(e)}"
112
205
  except Exception as e:
113
206
  logger.error(f"Failed to search exa {e}")
114
207
  return f"Error: {e}"
208
+
209
+ def get_contents(self, urls: list[str]) -> str:
210
+ """
211
+ Retrieve detailed content from specific URLs using the Exa API.
212
+
213
+ Args:
214
+ urls (list(str)): A list of URLs from which to fetch content.
215
+
216
+ Returns:
217
+ str: The search results in JSON format.
218
+ """
219
+
220
+ query_kwargs: Dict[str, Any] = {
221
+ "text": self.text,
222
+ "summary": self.summary,
223
+ }
224
+
225
+ try:
226
+ if self.show_results:
227
+ log_info(f"Fetching contents for URLs: {urls}")
228
+
229
+ # Execute get_contents with timeout
230
+ exa_results = self._execute_with_timeout(self.exa.get_contents, urls=urls, **query_kwargs)
231
+
232
+ parsed_results = self._parse_results(exa_results)
233
+ if self.show_results:
234
+ log_info(parsed_results)
235
+
236
+ return parsed_results
237
+ except TimeoutError as e:
238
+ logger.error(f"Get contents timed out after {self.timeout} seconds")
239
+ return f"Error: {str(e)}"
240
+ except Exception as e:
241
+ logger.error(f"Failed to get contents from Exa: {e}")
242
+ return f"Error: {e}"
243
+
244
+ def find_similar(self, url: str, num_results: int = 5) -> str:
245
+ """
246
+ Find similar links to a given URL using the Exa API.
247
+
248
+ Args:
249
+ url (str): The URL for which to find similar links.
250
+ num_results (int, optional): The number of similar links to return. Defaults to 5.
251
+
252
+ Returns:
253
+ str: The search results in JSON format.
254
+ """
255
+
256
+ query_kwargs: Dict[str, Any] = {
257
+ "text": self.text,
258
+ "summary": self.summary,
259
+ "include_domains": self.include_domains,
260
+ "exclude_domains": self.exclude_domains,
261
+ "start_crawl_date": self.start_crawl_date,
262
+ "end_crawl_date": self.end_crawl_date,
263
+ "start_published_date": self.start_published_date,
264
+ "end_published_date": self.end_published_date,
265
+ "num_results": self.num_results or num_results,
266
+ }
267
+
268
+ try:
269
+ if self.show_results:
270
+ log_info(f"Finding similar links to: {url}")
271
+
272
+ # Execute find_similar with timeout
273
+ exa_results = self._execute_with_timeout(self.exa.find_similar_and_contents, url=url, **query_kwargs)
274
+
275
+ parsed_results = self._parse_results(exa_results)
276
+ if self.show_results:
277
+ log_info(parsed_results)
278
+
279
+ return parsed_results
280
+ except TimeoutError as e:
281
+ logger.error(f"Find similar timed out after {self.timeout} seconds")
282
+ return f"Error: {str(e)}"
283
+ except Exception as e:
284
+ logger.error(f"Failed to get similar links from Exa: {e}")
285
+ return f"Error: {e}"
286
+
287
+ def exa_answer(self, query: str, text: bool = False) -> str:
288
+ """
289
+ Get an LLM answer to a question informed by Exa search results.
290
+
291
+ Args:
292
+ query (str): The question or query to answer.
293
+ text (bool): Include full text from citation. Default is False.
294
+ Returns:
295
+ str: The answer results in JSON format with both generated answer and sources.
296
+ """
297
+
298
+ if self.model and self.model not in ["exa", "exa-pro"]:
299
+ raise ValueError("Model must be either 'exa' or 'exa-pro'")
300
+ try:
301
+ if self.show_results:
302
+ log_info(f"Generating answer for query: {query}")
303
+ answer_kwargs: Dict[str, Any] = {
304
+ "model": self.model,
305
+ "text": text,
306
+ }
307
+ answer_kwargs = {k: v for k, v in answer_kwargs.items() if v is not None}
308
+
309
+ # Execute answer with timeout
310
+ answer = self._execute_with_timeout(self.exa.answer, query=query, **answer_kwargs)
311
+
312
+ result = {
313
+ "answer": answer.answer, # type: ignore
314
+ "citations": [
315
+ {
316
+ "id": citation.id,
317
+ "url": citation.url,
318
+ "title": citation.title,
319
+ "published_date": citation.published_date,
320
+ "author": citation.author,
321
+ "text": citation.text if text else None,
322
+ }
323
+ for citation in answer.citations # type: ignore
324
+ ],
325
+ }
326
+ if self.show_results:
327
+ log_info(json.dumps(result))
328
+
329
+ return json.dumps(result, indent=4)
330
+
331
+ except TimeoutError as e:
332
+ logger.error(f"Answer generation timed out after {self.timeout} seconds")
333
+ return f"Error: {str(e)}"
334
+ except Exception as e:
335
+ logger.error(f"Failed to get answer from Exa: {e}")
336
+ return f"Error: {e}"
337
+
338
+ def research(
339
+ self,
340
+ instructions: str,
341
+ output_schema: Optional[Dict[str, Any]] = None,
342
+ ) -> str:
343
+ """
344
+ Perform deep research on a topic.
345
+
346
+ Args:
347
+ instructions (str): Research instructions.
348
+ output_schema (Optional[Dict[str, Any]]): JSON schema for structured output. If not provided, the API will auto-infer an appropriate schema.
349
+ Returns:
350
+ str: JSON formatted research results including data and citations.
351
+ """
352
+ try:
353
+ log_debug(f"Creating research task with instructions: {instructions}")
354
+ log_debug(f"Output schema: {output_schema}")
355
+
356
+ task_kwargs: Dict[str, Any] = {
357
+ "instructions": instructions,
358
+ "model": self.research_model,
359
+ }
360
+
361
+ if output_schema is not None:
362
+ task_kwargs["output_schema"] = output_schema
363
+ else:
364
+ task_kwargs["output_infer_schema"] = True
365
+
366
+ task_result = self._execute_with_timeout(self.exa.research.create_task, **task_kwargs) # type: ignore
367
+ task_id = task_result.id
368
+
369
+ if self.show_results:
370
+ log_info(f"Research task created with ID: {task_id}")
371
+
372
+ # Step 2: Poll until complete (using default polling settings)
373
+ task = self.exa.research.poll_task(task_id) # type: ignore
374
+
375
+ # Step 3: Format and return results
376
+ result: Dict[str, Any] = {"data": task.data, "citations": {}}
377
+
378
+ # Process citations by field
379
+ for field, sources in task.citations.items():
380
+ result["citations"][field] = [
381
+ {"url": source.url, "title": source.title, "id": source.id} for source in sources
382
+ ]
383
+
384
+ if self.show_results:
385
+ log_info("Research completed successfully")
386
+
387
+ return json.dumps(result, indent=4)
388
+
389
+ except TimeoutError:
390
+ error_msg = "Research task timed out"
391
+ logger.error(error_msg)
392
+ return json.dumps({"error": error_msg}, indent=4)
393
+ except Exception as e:
394
+ error_msg = f"Research failed: {str(e)}"
395
+ logger.error(error_msg)
396
+ return json.dumps({"error": error_msg}, indent=4)
agno/tools/fal.py CHANGED
@@ -3,13 +3,15 @@ pip install fal-client
3
3
  """
4
4
 
5
5
  from os import getenv
6
- from typing import Optional
6
+ 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
+ from agno.team.team import Team
11
12
  from agno.tools import Toolkit
12
- from agno.utils.log import logger
13
+ from agno.tools.function import ToolResult
14
+ from agno.utils.log import log_info, logger
13
15
 
14
16
  try:
15
17
  import fal_client # type: ignore
@@ -22,32 +24,41 @@ class FalTools(Toolkit):
22
24
  self,
23
25
  api_key: Optional[str] = None,
24
26
  model: str = "fal-ai/hunyuan-video",
27
+ enable_generate_media: bool = True,
28
+ enable_image_to_image: bool = False,
29
+ all: bool = False,
30
+ **kwargs,
25
31
  ):
26
- super().__init__(name="fal")
27
-
28
- self.api_key = api_key or getenv("FAL_KEY")
32
+ self.api_key = api_key or getenv("FAL_API_KEY")
29
33
  if not self.api_key:
30
- logger.error("FAL_KEY not set. Please set the FAL_KEY environment variable.")
34
+ logger.error("FAL_API_KEY not set. Please set the FAL_API_KEY environment variable.")
31
35
  self.model = model
32
36
  self.seen_logs: set[str] = set()
33
- self.register(self.generate_media)
37
+
38
+ tools = []
39
+ if all or enable_generate_media:
40
+ tools.append(self.generate_media)
41
+ if all or enable_image_to_image:
42
+ tools.append(self.image_to_image)
43
+
44
+ super().__init__(name="fal-tools", tools=tools, **kwargs)
34
45
 
35
46
  def on_queue_update(self, update):
36
47
  if isinstance(update, fal_client.InProgress) and update.logs:
37
48
  for log in update.logs:
38
49
  message = log["message"]
39
50
  if message not in self.seen_logs:
40
- logger.info(message)
51
+ log_info(message)
41
52
  self.seen_logs.add(message)
42
53
 
43
- def generate_media(self, agent: Agent, prompt: str) -> str:
54
+ def generate_media(self, agent: Union[Agent, Team], prompt: str) -> ToolResult:
44
55
  """
45
56
  Use this function to run a model with a given prompt.
46
57
 
47
58
  Args:
48
59
  prompt (str): A text description of the task.
49
60
  Returns:
50
- str: Return the result of the model.
61
+ ToolResult: Contains the generated media and success message.
51
62
  """
52
63
  try:
53
64
  result = fal_client.subscribe(
@@ -61,32 +72,27 @@ class FalTools(Toolkit):
61
72
 
62
73
  if "image" in result:
63
74
  url = result.get("image", {}).get("url", "")
64
- agent.add_image(
65
- ImageArtifact(
66
- id=media_id,
67
- url=url,
68
- )
75
+ image_artifact = Image(
76
+ id=media_id,
77
+ url=url,
69
78
  )
70
- media_type = "image"
79
+ return ToolResult(content=f"Image generated successfully at {url}", images=[image_artifact])
71
80
  elif "video" in result:
72
81
  url = result.get("video", {}).get("url", "")
73
- agent.add_video(
74
- VideoArtifact(
75
- id=media_id,
76
- url=url,
77
- )
82
+ video_artifact = Video(
83
+ id=media_id,
84
+ url=url,
78
85
  )
79
- media_type = "video"
86
+ return ToolResult(content=f"Video generated successfully at {url}", videos=[video_artifact])
80
87
  else:
81
88
  logger.error(f"Unsupported type in result: {result}")
82
- return f"Unsupported type in result: {result}"
89
+ return ToolResult(content=f"Unsupported type in result: {result}")
83
90
 
84
- return f"{media_type.capitalize()} generated successfully at {url}"
85
91
  except Exception as e:
86
92
  logger.error(f"Failed to run model: {e}")
87
- return f"Error: {e}"
93
+ return ToolResult(content=f"Error: {e}")
88
94
 
89
- def image_to_image(self, agent: Agent, prompt: str, image_url: Optional[str] = None) -> str:
95
+ def image_to_image(self, agent: Union[Agent, Team], prompt: str, image_url: Optional[str] = None) -> ToolResult:
90
96
  """
91
97
  Use this function to transform an input image based on a text prompt using the Fal AI image-to-image model.
92
98
  The model takes an existing image and generates a new version modified according to your prompt.
@@ -97,7 +103,7 @@ class FalTools(Toolkit):
97
103
  image_url (str): The URL of the image to use for the generation.
98
104
 
99
105
  Returns:
100
- str: Return the result of the model.
106
+ ToolResult: Contains the generated image and success message.
101
107
  """
102
108
 
103
109
  try:
@@ -109,15 +115,13 @@ class FalTools(Toolkit):
109
115
  )
110
116
  url = result.get("images", [{}])[0].get("url", "")
111
117
  media_id = str(uuid4())
112
- agent.add_image(
113
- ImageArtifact(
114
- id=media_id,
115
- url=url,
116
- )
118
+ image_artifact = Image(
119
+ id=media_id,
120
+ url=url,
117
121
  )
118
122
 
119
- return f"Image generated successfully at {url}"
123
+ return ToolResult(content=f"Image generated successfully at {url}", images=[image_artifact])
120
124
 
121
125
  except Exception as e:
122
126
  logger.error(f"Failed to generate image: {e}")
123
- return f"Error: {e}"
127
+ return ToolResult(content=f"Error: {e}")