agno 2.2.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 (575) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +51 -0
  3. agno/agent/agent.py +10405 -0
  4. agno/api/__init__.py +0 -0
  5. agno/api/agent.py +28 -0
  6. agno/api/api.py +40 -0
  7. agno/api/evals.py +22 -0
  8. agno/api/os.py +17 -0
  9. agno/api/routes.py +13 -0
  10. agno/api/schemas/__init__.py +9 -0
  11. agno/api/schemas/agent.py +16 -0
  12. agno/api/schemas/evals.py +16 -0
  13. agno/api/schemas/os.py +14 -0
  14. agno/api/schemas/response.py +6 -0
  15. agno/api/schemas/team.py +16 -0
  16. agno/api/schemas/utils.py +21 -0
  17. agno/api/schemas/workflows.py +16 -0
  18. agno/api/settings.py +53 -0
  19. agno/api/team.py +30 -0
  20. agno/api/workflow.py +28 -0
  21. agno/cloud/aws/base.py +214 -0
  22. agno/cloud/aws/s3/__init__.py +2 -0
  23. agno/cloud/aws/s3/api_client.py +43 -0
  24. agno/cloud/aws/s3/bucket.py +195 -0
  25. agno/cloud/aws/s3/object.py +57 -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 +598 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2042 -0
  33. agno/db/dynamo/schemas.py +314 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +1795 -0
  37. agno/db/firestore/schemas.py +140 -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 +1335 -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 +1160 -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 +1328 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/__init__.py +0 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/mongo/__init__.py +17 -0
  51. agno/db/mongo/async_mongo.py +2026 -0
  52. agno/db/mongo/mongo.py +1982 -0
  53. agno/db/mongo/schemas.py +87 -0
  54. agno/db/mongo/utils.py +259 -0
  55. agno/db/mysql/__init__.py +3 -0
  56. agno/db/mysql/mysql.py +2308 -0
  57. agno/db/mysql/schemas.py +138 -0
  58. agno/db/mysql/utils.py +355 -0
  59. agno/db/postgres/__init__.py +4 -0
  60. agno/db/postgres/async_postgres.py +1927 -0
  61. agno/db/postgres/postgres.py +2260 -0
  62. agno/db/postgres/schemas.py +139 -0
  63. agno/db/postgres/utils.py +442 -0
  64. agno/db/redis/__init__.py +3 -0
  65. agno/db/redis/redis.py +1660 -0
  66. agno/db/redis/schemas.py +123 -0
  67. agno/db/redis/utils.py +346 -0
  68. agno/db/schemas/__init__.py +4 -0
  69. agno/db/schemas/culture.py +120 -0
  70. agno/db/schemas/evals.py +33 -0
  71. agno/db/schemas/knowledge.py +40 -0
  72. agno/db/schemas/memory.py +46 -0
  73. agno/db/schemas/metrics.py +0 -0
  74. agno/db/singlestore/__init__.py +3 -0
  75. agno/db/singlestore/schemas.py +130 -0
  76. agno/db/singlestore/singlestore.py +2272 -0
  77. agno/db/singlestore/utils.py +384 -0
  78. agno/db/sqlite/__init__.py +4 -0
  79. agno/db/sqlite/async_sqlite.py +2293 -0
  80. agno/db/sqlite/schemas.py +133 -0
  81. agno/db/sqlite/sqlite.py +2288 -0
  82. agno/db/sqlite/utils.py +431 -0
  83. agno/db/surrealdb/__init__.py +3 -0
  84. agno/db/surrealdb/metrics.py +292 -0
  85. agno/db/surrealdb/models.py +309 -0
  86. agno/db/surrealdb/queries.py +71 -0
  87. agno/db/surrealdb/surrealdb.py +1353 -0
  88. agno/db/surrealdb/utils.py +147 -0
  89. agno/db/utils.py +116 -0
  90. agno/debug.py +18 -0
  91. agno/eval/__init__.py +14 -0
  92. agno/eval/accuracy.py +834 -0
  93. agno/eval/performance.py +773 -0
  94. agno/eval/reliability.py +306 -0
  95. agno/eval/utils.py +119 -0
  96. agno/exceptions.py +161 -0
  97. agno/filters.py +354 -0
  98. agno/guardrails/__init__.py +6 -0
  99. agno/guardrails/base.py +19 -0
  100. agno/guardrails/openai.py +144 -0
  101. agno/guardrails/pii.py +94 -0
  102. agno/guardrails/prompt_injection.py +52 -0
  103. agno/integrations/__init__.py +0 -0
  104. agno/integrations/discord/__init__.py +3 -0
  105. agno/integrations/discord/client.py +203 -0
  106. agno/knowledge/__init__.py +5 -0
  107. agno/knowledge/chunking/__init__.py +0 -0
  108. agno/knowledge/chunking/agentic.py +79 -0
  109. agno/knowledge/chunking/document.py +91 -0
  110. agno/knowledge/chunking/fixed.py +57 -0
  111. agno/knowledge/chunking/markdown.py +151 -0
  112. agno/knowledge/chunking/recursive.py +63 -0
  113. agno/knowledge/chunking/row.py +39 -0
  114. agno/knowledge/chunking/semantic.py +86 -0
  115. agno/knowledge/chunking/strategy.py +165 -0
  116. agno/knowledge/content.py +74 -0
  117. agno/knowledge/document/__init__.py +5 -0
  118. agno/knowledge/document/base.py +58 -0
  119. agno/knowledge/embedder/__init__.py +5 -0
  120. agno/knowledge/embedder/aws_bedrock.py +343 -0
  121. agno/knowledge/embedder/azure_openai.py +210 -0
  122. agno/knowledge/embedder/base.py +23 -0
  123. agno/knowledge/embedder/cohere.py +323 -0
  124. agno/knowledge/embedder/fastembed.py +62 -0
  125. agno/knowledge/embedder/fireworks.py +13 -0
  126. agno/knowledge/embedder/google.py +258 -0
  127. agno/knowledge/embedder/huggingface.py +94 -0
  128. agno/knowledge/embedder/jina.py +182 -0
  129. agno/knowledge/embedder/langdb.py +22 -0
  130. agno/knowledge/embedder/mistral.py +206 -0
  131. agno/knowledge/embedder/nebius.py +13 -0
  132. agno/knowledge/embedder/ollama.py +154 -0
  133. agno/knowledge/embedder/openai.py +195 -0
  134. agno/knowledge/embedder/sentence_transformer.py +63 -0
  135. agno/knowledge/embedder/together.py +13 -0
  136. agno/knowledge/embedder/vllm.py +262 -0
  137. agno/knowledge/embedder/voyageai.py +165 -0
  138. agno/knowledge/knowledge.py +1988 -0
  139. agno/knowledge/reader/__init__.py +7 -0
  140. agno/knowledge/reader/arxiv_reader.py +81 -0
  141. agno/knowledge/reader/base.py +95 -0
  142. agno/knowledge/reader/csv_reader.py +166 -0
  143. agno/knowledge/reader/docx_reader.py +82 -0
  144. agno/knowledge/reader/field_labeled_csv_reader.py +292 -0
  145. agno/knowledge/reader/firecrawl_reader.py +201 -0
  146. agno/knowledge/reader/json_reader.py +87 -0
  147. agno/knowledge/reader/markdown_reader.py +137 -0
  148. agno/knowledge/reader/pdf_reader.py +431 -0
  149. agno/knowledge/reader/pptx_reader.py +101 -0
  150. agno/knowledge/reader/reader_factory.py +313 -0
  151. agno/knowledge/reader/s3_reader.py +89 -0
  152. agno/knowledge/reader/tavily_reader.py +194 -0
  153. agno/knowledge/reader/text_reader.py +115 -0
  154. agno/knowledge/reader/web_search_reader.py +372 -0
  155. agno/knowledge/reader/website_reader.py +455 -0
  156. agno/knowledge/reader/wikipedia_reader.py +59 -0
  157. agno/knowledge/reader/youtube_reader.py +78 -0
  158. agno/knowledge/remote_content/__init__.py +0 -0
  159. agno/knowledge/remote_content/remote_content.py +88 -0
  160. agno/knowledge/reranker/__init__.py +3 -0
  161. agno/knowledge/reranker/base.py +14 -0
  162. agno/knowledge/reranker/cohere.py +64 -0
  163. agno/knowledge/reranker/infinity.py +195 -0
  164. agno/knowledge/reranker/sentence_transformer.py +54 -0
  165. agno/knowledge/types.py +39 -0
  166. agno/knowledge/utils.py +189 -0
  167. agno/media.py +462 -0
  168. agno/memory/__init__.py +3 -0
  169. agno/memory/manager.py +1327 -0
  170. agno/models/__init__.py +0 -0
  171. agno/models/aimlapi/__init__.py +5 -0
  172. agno/models/aimlapi/aimlapi.py +45 -0
  173. agno/models/anthropic/__init__.py +5 -0
  174. agno/models/anthropic/claude.py +757 -0
  175. agno/models/aws/__init__.py +15 -0
  176. agno/models/aws/bedrock.py +701 -0
  177. agno/models/aws/claude.py +378 -0
  178. agno/models/azure/__init__.py +18 -0
  179. agno/models/azure/ai_foundry.py +485 -0
  180. agno/models/azure/openai_chat.py +131 -0
  181. agno/models/base.py +2175 -0
  182. agno/models/cerebras/__init__.py +12 -0
  183. agno/models/cerebras/cerebras.py +501 -0
  184. agno/models/cerebras/cerebras_openai.py +112 -0
  185. agno/models/cohere/__init__.py +5 -0
  186. agno/models/cohere/chat.py +389 -0
  187. agno/models/cometapi/__init__.py +5 -0
  188. agno/models/cometapi/cometapi.py +57 -0
  189. agno/models/dashscope/__init__.py +5 -0
  190. agno/models/dashscope/dashscope.py +91 -0
  191. agno/models/deepinfra/__init__.py +5 -0
  192. agno/models/deepinfra/deepinfra.py +28 -0
  193. agno/models/deepseek/__init__.py +5 -0
  194. agno/models/deepseek/deepseek.py +61 -0
  195. agno/models/defaults.py +1 -0
  196. agno/models/fireworks/__init__.py +5 -0
  197. agno/models/fireworks/fireworks.py +26 -0
  198. agno/models/google/__init__.py +5 -0
  199. agno/models/google/gemini.py +1085 -0
  200. agno/models/groq/__init__.py +5 -0
  201. agno/models/groq/groq.py +556 -0
  202. agno/models/huggingface/__init__.py +5 -0
  203. agno/models/huggingface/huggingface.py +491 -0
  204. agno/models/ibm/__init__.py +5 -0
  205. agno/models/ibm/watsonx.py +422 -0
  206. agno/models/internlm/__init__.py +3 -0
  207. agno/models/internlm/internlm.py +26 -0
  208. agno/models/langdb/__init__.py +1 -0
  209. agno/models/langdb/langdb.py +48 -0
  210. agno/models/litellm/__init__.py +14 -0
  211. agno/models/litellm/chat.py +468 -0
  212. agno/models/litellm/litellm_openai.py +25 -0
  213. agno/models/llama_cpp/__init__.py +5 -0
  214. agno/models/llama_cpp/llama_cpp.py +22 -0
  215. agno/models/lmstudio/__init__.py +5 -0
  216. agno/models/lmstudio/lmstudio.py +25 -0
  217. agno/models/message.py +434 -0
  218. agno/models/meta/__init__.py +12 -0
  219. agno/models/meta/llama.py +475 -0
  220. agno/models/meta/llama_openai.py +78 -0
  221. agno/models/metrics.py +120 -0
  222. agno/models/mistral/__init__.py +5 -0
  223. agno/models/mistral/mistral.py +432 -0
  224. agno/models/nebius/__init__.py +3 -0
  225. agno/models/nebius/nebius.py +54 -0
  226. agno/models/nexus/__init__.py +3 -0
  227. agno/models/nexus/nexus.py +22 -0
  228. agno/models/nvidia/__init__.py +5 -0
  229. agno/models/nvidia/nvidia.py +28 -0
  230. agno/models/ollama/__init__.py +5 -0
  231. agno/models/ollama/chat.py +441 -0
  232. agno/models/openai/__init__.py +9 -0
  233. agno/models/openai/chat.py +883 -0
  234. agno/models/openai/like.py +27 -0
  235. agno/models/openai/responses.py +1050 -0
  236. agno/models/openrouter/__init__.py +5 -0
  237. agno/models/openrouter/openrouter.py +66 -0
  238. agno/models/perplexity/__init__.py +5 -0
  239. agno/models/perplexity/perplexity.py +187 -0
  240. agno/models/portkey/__init__.py +3 -0
  241. agno/models/portkey/portkey.py +81 -0
  242. agno/models/requesty/__init__.py +5 -0
  243. agno/models/requesty/requesty.py +52 -0
  244. agno/models/response.py +199 -0
  245. agno/models/sambanova/__init__.py +5 -0
  246. agno/models/sambanova/sambanova.py +28 -0
  247. agno/models/siliconflow/__init__.py +5 -0
  248. agno/models/siliconflow/siliconflow.py +25 -0
  249. agno/models/together/__init__.py +5 -0
  250. agno/models/together/together.py +25 -0
  251. agno/models/utils.py +266 -0
  252. agno/models/vercel/__init__.py +3 -0
  253. agno/models/vercel/v0.py +26 -0
  254. agno/models/vertexai/__init__.py +0 -0
  255. agno/models/vertexai/claude.py +70 -0
  256. agno/models/vllm/__init__.py +3 -0
  257. agno/models/vllm/vllm.py +78 -0
  258. agno/models/xai/__init__.py +3 -0
  259. agno/models/xai/xai.py +113 -0
  260. agno/os/__init__.py +3 -0
  261. agno/os/app.py +876 -0
  262. agno/os/auth.py +57 -0
  263. agno/os/config.py +104 -0
  264. agno/os/interfaces/__init__.py +1 -0
  265. agno/os/interfaces/a2a/__init__.py +3 -0
  266. agno/os/interfaces/a2a/a2a.py +42 -0
  267. agno/os/interfaces/a2a/router.py +250 -0
  268. agno/os/interfaces/a2a/utils.py +924 -0
  269. agno/os/interfaces/agui/__init__.py +3 -0
  270. agno/os/interfaces/agui/agui.py +47 -0
  271. agno/os/interfaces/agui/router.py +144 -0
  272. agno/os/interfaces/agui/utils.py +534 -0
  273. agno/os/interfaces/base.py +25 -0
  274. agno/os/interfaces/slack/__init__.py +3 -0
  275. agno/os/interfaces/slack/router.py +148 -0
  276. agno/os/interfaces/slack/security.py +30 -0
  277. agno/os/interfaces/slack/slack.py +47 -0
  278. agno/os/interfaces/whatsapp/__init__.py +3 -0
  279. agno/os/interfaces/whatsapp/router.py +211 -0
  280. agno/os/interfaces/whatsapp/security.py +53 -0
  281. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  282. agno/os/mcp.py +292 -0
  283. agno/os/middleware/__init__.py +7 -0
  284. agno/os/middleware/jwt.py +233 -0
  285. agno/os/router.py +1763 -0
  286. agno/os/routers/__init__.py +3 -0
  287. agno/os/routers/evals/__init__.py +3 -0
  288. agno/os/routers/evals/evals.py +430 -0
  289. agno/os/routers/evals/schemas.py +142 -0
  290. agno/os/routers/evals/utils.py +162 -0
  291. agno/os/routers/health.py +31 -0
  292. agno/os/routers/home.py +52 -0
  293. agno/os/routers/knowledge/__init__.py +3 -0
  294. agno/os/routers/knowledge/knowledge.py +997 -0
  295. agno/os/routers/knowledge/schemas.py +178 -0
  296. agno/os/routers/memory/__init__.py +3 -0
  297. agno/os/routers/memory/memory.py +515 -0
  298. agno/os/routers/memory/schemas.py +62 -0
  299. agno/os/routers/metrics/__init__.py +3 -0
  300. agno/os/routers/metrics/metrics.py +190 -0
  301. agno/os/routers/metrics/schemas.py +47 -0
  302. agno/os/routers/session/__init__.py +3 -0
  303. agno/os/routers/session/session.py +997 -0
  304. agno/os/schema.py +1055 -0
  305. agno/os/settings.py +43 -0
  306. agno/os/utils.py +630 -0
  307. agno/py.typed +0 -0
  308. agno/reasoning/__init__.py +0 -0
  309. agno/reasoning/anthropic.py +80 -0
  310. agno/reasoning/azure_ai_foundry.py +67 -0
  311. agno/reasoning/deepseek.py +63 -0
  312. agno/reasoning/default.py +97 -0
  313. agno/reasoning/gemini.py +73 -0
  314. agno/reasoning/groq.py +71 -0
  315. agno/reasoning/helpers.py +63 -0
  316. agno/reasoning/ollama.py +67 -0
  317. agno/reasoning/openai.py +86 -0
  318. agno/reasoning/step.py +31 -0
  319. agno/reasoning/vertexai.py +76 -0
  320. agno/run/__init__.py +6 -0
  321. agno/run/agent.py +787 -0
  322. agno/run/base.py +229 -0
  323. agno/run/cancel.py +81 -0
  324. agno/run/messages.py +32 -0
  325. agno/run/team.py +753 -0
  326. agno/run/workflow.py +708 -0
  327. agno/session/__init__.py +10 -0
  328. agno/session/agent.py +295 -0
  329. agno/session/summary.py +265 -0
  330. agno/session/team.py +392 -0
  331. agno/session/workflow.py +205 -0
  332. agno/team/__init__.py +37 -0
  333. agno/team/team.py +8793 -0
  334. agno/tools/__init__.py +10 -0
  335. agno/tools/agentql.py +120 -0
  336. agno/tools/airflow.py +69 -0
  337. agno/tools/api.py +122 -0
  338. agno/tools/apify.py +314 -0
  339. agno/tools/arxiv.py +127 -0
  340. agno/tools/aws_lambda.py +53 -0
  341. agno/tools/aws_ses.py +66 -0
  342. agno/tools/baidusearch.py +89 -0
  343. agno/tools/bitbucket.py +292 -0
  344. agno/tools/brandfetch.py +213 -0
  345. agno/tools/bravesearch.py +106 -0
  346. agno/tools/brightdata.py +367 -0
  347. agno/tools/browserbase.py +209 -0
  348. agno/tools/calcom.py +255 -0
  349. agno/tools/calculator.py +151 -0
  350. agno/tools/cartesia.py +187 -0
  351. agno/tools/clickup.py +244 -0
  352. agno/tools/confluence.py +240 -0
  353. agno/tools/crawl4ai.py +158 -0
  354. agno/tools/csv_toolkit.py +185 -0
  355. agno/tools/dalle.py +110 -0
  356. agno/tools/daytona.py +475 -0
  357. agno/tools/decorator.py +262 -0
  358. agno/tools/desi_vocal.py +108 -0
  359. agno/tools/discord.py +161 -0
  360. agno/tools/docker.py +716 -0
  361. agno/tools/duckdb.py +379 -0
  362. agno/tools/duckduckgo.py +91 -0
  363. agno/tools/e2b.py +703 -0
  364. agno/tools/eleven_labs.py +196 -0
  365. agno/tools/email.py +67 -0
  366. agno/tools/evm.py +129 -0
  367. agno/tools/exa.py +396 -0
  368. agno/tools/fal.py +127 -0
  369. agno/tools/file.py +240 -0
  370. agno/tools/file_generation.py +350 -0
  371. agno/tools/financial_datasets.py +288 -0
  372. agno/tools/firecrawl.py +143 -0
  373. agno/tools/function.py +1187 -0
  374. agno/tools/giphy.py +93 -0
  375. agno/tools/github.py +1760 -0
  376. agno/tools/gmail.py +922 -0
  377. agno/tools/google_bigquery.py +117 -0
  378. agno/tools/google_drive.py +270 -0
  379. agno/tools/google_maps.py +253 -0
  380. agno/tools/googlecalendar.py +674 -0
  381. agno/tools/googlesearch.py +98 -0
  382. agno/tools/googlesheets.py +377 -0
  383. agno/tools/hackernews.py +77 -0
  384. agno/tools/jina.py +101 -0
  385. agno/tools/jira.py +170 -0
  386. agno/tools/knowledge.py +218 -0
  387. agno/tools/linear.py +426 -0
  388. agno/tools/linkup.py +58 -0
  389. agno/tools/local_file_system.py +90 -0
  390. agno/tools/lumalab.py +183 -0
  391. agno/tools/mcp/__init__.py +10 -0
  392. agno/tools/mcp/mcp.py +331 -0
  393. agno/tools/mcp/multi_mcp.py +347 -0
  394. agno/tools/mcp/params.py +24 -0
  395. agno/tools/mcp_toolbox.py +284 -0
  396. agno/tools/mem0.py +193 -0
  397. agno/tools/memori.py +339 -0
  398. agno/tools/memory.py +419 -0
  399. agno/tools/mlx_transcribe.py +139 -0
  400. agno/tools/models/__init__.py +0 -0
  401. agno/tools/models/azure_openai.py +190 -0
  402. agno/tools/models/gemini.py +203 -0
  403. agno/tools/models/groq.py +158 -0
  404. agno/tools/models/morph.py +186 -0
  405. agno/tools/models/nebius.py +124 -0
  406. agno/tools/models_labs.py +195 -0
  407. agno/tools/moviepy_video.py +349 -0
  408. agno/tools/neo4j.py +134 -0
  409. agno/tools/newspaper.py +46 -0
  410. agno/tools/newspaper4k.py +93 -0
  411. agno/tools/notion.py +204 -0
  412. agno/tools/openai.py +202 -0
  413. agno/tools/openbb.py +160 -0
  414. agno/tools/opencv.py +321 -0
  415. agno/tools/openweather.py +233 -0
  416. agno/tools/oxylabs.py +385 -0
  417. agno/tools/pandas.py +102 -0
  418. agno/tools/parallel.py +314 -0
  419. agno/tools/postgres.py +257 -0
  420. agno/tools/pubmed.py +188 -0
  421. agno/tools/python.py +205 -0
  422. agno/tools/reasoning.py +283 -0
  423. agno/tools/reddit.py +467 -0
  424. agno/tools/replicate.py +117 -0
  425. agno/tools/resend.py +62 -0
  426. agno/tools/scrapegraph.py +222 -0
  427. agno/tools/searxng.py +152 -0
  428. agno/tools/serpapi.py +116 -0
  429. agno/tools/serper.py +255 -0
  430. agno/tools/shell.py +53 -0
  431. agno/tools/slack.py +136 -0
  432. agno/tools/sleep.py +20 -0
  433. agno/tools/spider.py +116 -0
  434. agno/tools/sql.py +154 -0
  435. agno/tools/streamlit/__init__.py +0 -0
  436. agno/tools/streamlit/components.py +113 -0
  437. agno/tools/tavily.py +254 -0
  438. agno/tools/telegram.py +48 -0
  439. agno/tools/todoist.py +218 -0
  440. agno/tools/tool_registry.py +1 -0
  441. agno/tools/toolkit.py +146 -0
  442. agno/tools/trafilatura.py +388 -0
  443. agno/tools/trello.py +274 -0
  444. agno/tools/twilio.py +186 -0
  445. agno/tools/user_control_flow.py +78 -0
  446. agno/tools/valyu.py +228 -0
  447. agno/tools/visualization.py +467 -0
  448. agno/tools/webbrowser.py +28 -0
  449. agno/tools/webex.py +76 -0
  450. agno/tools/website.py +54 -0
  451. agno/tools/webtools.py +45 -0
  452. agno/tools/whatsapp.py +286 -0
  453. agno/tools/wikipedia.py +63 -0
  454. agno/tools/workflow.py +278 -0
  455. agno/tools/x.py +335 -0
  456. agno/tools/yfinance.py +257 -0
  457. agno/tools/youtube.py +184 -0
  458. agno/tools/zendesk.py +82 -0
  459. agno/tools/zep.py +454 -0
  460. agno/tools/zoom.py +382 -0
  461. agno/utils/__init__.py +0 -0
  462. agno/utils/agent.py +820 -0
  463. agno/utils/audio.py +49 -0
  464. agno/utils/certs.py +27 -0
  465. agno/utils/code_execution.py +11 -0
  466. agno/utils/common.py +132 -0
  467. agno/utils/dttm.py +13 -0
  468. agno/utils/enum.py +22 -0
  469. agno/utils/env.py +11 -0
  470. agno/utils/events.py +696 -0
  471. agno/utils/format_str.py +16 -0
  472. agno/utils/functions.py +166 -0
  473. agno/utils/gemini.py +426 -0
  474. agno/utils/hooks.py +57 -0
  475. agno/utils/http.py +74 -0
  476. agno/utils/json_schema.py +234 -0
  477. agno/utils/knowledge.py +36 -0
  478. agno/utils/location.py +19 -0
  479. agno/utils/log.py +255 -0
  480. agno/utils/mcp.py +214 -0
  481. agno/utils/media.py +352 -0
  482. agno/utils/merge_dict.py +41 -0
  483. agno/utils/message.py +118 -0
  484. agno/utils/models/__init__.py +0 -0
  485. agno/utils/models/ai_foundry.py +43 -0
  486. agno/utils/models/claude.py +358 -0
  487. agno/utils/models/cohere.py +87 -0
  488. agno/utils/models/llama.py +78 -0
  489. agno/utils/models/mistral.py +98 -0
  490. agno/utils/models/openai_responses.py +140 -0
  491. agno/utils/models/schema_utils.py +153 -0
  492. agno/utils/models/watsonx.py +41 -0
  493. agno/utils/openai.py +257 -0
  494. agno/utils/pickle.py +32 -0
  495. agno/utils/pprint.py +178 -0
  496. agno/utils/print_response/__init__.py +0 -0
  497. agno/utils/print_response/agent.py +842 -0
  498. agno/utils/print_response/team.py +1724 -0
  499. agno/utils/print_response/workflow.py +1668 -0
  500. agno/utils/prompts.py +111 -0
  501. agno/utils/reasoning.py +108 -0
  502. agno/utils/response.py +163 -0
  503. agno/utils/response_iterator.py +17 -0
  504. agno/utils/safe_formatter.py +24 -0
  505. agno/utils/serialize.py +32 -0
  506. agno/utils/shell.py +22 -0
  507. agno/utils/streamlit.py +487 -0
  508. agno/utils/string.py +231 -0
  509. agno/utils/team.py +139 -0
  510. agno/utils/timer.py +41 -0
  511. agno/utils/tools.py +102 -0
  512. agno/utils/web.py +23 -0
  513. agno/utils/whatsapp.py +305 -0
  514. agno/utils/yaml_io.py +25 -0
  515. agno/vectordb/__init__.py +3 -0
  516. agno/vectordb/base.py +127 -0
  517. agno/vectordb/cassandra/__init__.py +5 -0
  518. agno/vectordb/cassandra/cassandra.py +501 -0
  519. agno/vectordb/cassandra/extra_param_mixin.py +11 -0
  520. agno/vectordb/cassandra/index.py +13 -0
  521. agno/vectordb/chroma/__init__.py +5 -0
  522. agno/vectordb/chroma/chromadb.py +929 -0
  523. agno/vectordb/clickhouse/__init__.py +9 -0
  524. agno/vectordb/clickhouse/clickhousedb.py +835 -0
  525. agno/vectordb/clickhouse/index.py +9 -0
  526. agno/vectordb/couchbase/__init__.py +3 -0
  527. agno/vectordb/couchbase/couchbase.py +1442 -0
  528. agno/vectordb/distance.py +7 -0
  529. agno/vectordb/lancedb/__init__.py +6 -0
  530. agno/vectordb/lancedb/lance_db.py +995 -0
  531. agno/vectordb/langchaindb/__init__.py +5 -0
  532. agno/vectordb/langchaindb/langchaindb.py +163 -0
  533. agno/vectordb/lightrag/__init__.py +5 -0
  534. agno/vectordb/lightrag/lightrag.py +388 -0
  535. agno/vectordb/llamaindex/__init__.py +3 -0
  536. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  537. agno/vectordb/milvus/__init__.py +4 -0
  538. agno/vectordb/milvus/milvus.py +1182 -0
  539. agno/vectordb/mongodb/__init__.py +9 -0
  540. agno/vectordb/mongodb/mongodb.py +1417 -0
  541. agno/vectordb/pgvector/__init__.py +12 -0
  542. agno/vectordb/pgvector/index.py +23 -0
  543. agno/vectordb/pgvector/pgvector.py +1462 -0
  544. agno/vectordb/pineconedb/__init__.py +5 -0
  545. agno/vectordb/pineconedb/pineconedb.py +747 -0
  546. agno/vectordb/qdrant/__init__.py +5 -0
  547. agno/vectordb/qdrant/qdrant.py +1134 -0
  548. agno/vectordb/redis/__init__.py +9 -0
  549. agno/vectordb/redis/redisdb.py +694 -0
  550. agno/vectordb/search.py +7 -0
  551. agno/vectordb/singlestore/__init__.py +10 -0
  552. agno/vectordb/singlestore/index.py +41 -0
  553. agno/vectordb/singlestore/singlestore.py +763 -0
  554. agno/vectordb/surrealdb/__init__.py +3 -0
  555. agno/vectordb/surrealdb/surrealdb.py +699 -0
  556. agno/vectordb/upstashdb/__init__.py +5 -0
  557. agno/vectordb/upstashdb/upstashdb.py +718 -0
  558. agno/vectordb/weaviate/__init__.py +8 -0
  559. agno/vectordb/weaviate/index.py +15 -0
  560. agno/vectordb/weaviate/weaviate.py +1005 -0
  561. agno/workflow/__init__.py +23 -0
  562. agno/workflow/agent.py +299 -0
  563. agno/workflow/condition.py +738 -0
  564. agno/workflow/loop.py +735 -0
  565. agno/workflow/parallel.py +824 -0
  566. agno/workflow/router.py +702 -0
  567. agno/workflow/step.py +1432 -0
  568. agno/workflow/steps.py +592 -0
  569. agno/workflow/types.py +520 -0
  570. agno/workflow/workflow.py +4321 -0
  571. agno-2.2.13.dist-info/METADATA +614 -0
  572. agno-2.2.13.dist-info/RECORD +575 -0
  573. agno-2.2.13.dist-info/WHEEL +5 -0
  574. agno-2.2.13.dist-info/licenses/LICENSE +201 -0
  575. agno-2.2.13.dist-info/top_level.txt +1 -0
agno/tools/reddit.py ADDED
@@ -0,0 +1,467 @@
1
+ import json
2
+ from os import getenv
3
+ from typing import Callable, Dict, List, Optional, Union
4
+
5
+ from agno.tools import Toolkit
6
+ from agno.utils.log import log_debug, log_info, logger
7
+
8
+ try:
9
+ import praw # type: ignore
10
+ except ImportError:
11
+ raise ImportError("praw` not installed. Please install using `pip install praw`")
12
+
13
+
14
+ class RedditTools(Toolkit):
15
+ def __init__(
16
+ self,
17
+ reddit_instance: Optional[praw.Reddit] = None,
18
+ client_id: Optional[str] = None,
19
+ client_secret: Optional[str] = None,
20
+ user_agent: Optional[str] = None,
21
+ username: Optional[str] = None,
22
+ password: Optional[str] = None,
23
+ **kwargs,
24
+ ):
25
+ if reddit_instance is not None:
26
+ log_info("Using provided Reddit instance")
27
+ self.reddit = reddit_instance
28
+ else:
29
+ # Get credentials from environment variables if not provided
30
+ self.client_id = client_id or getenv("REDDIT_CLIENT_ID")
31
+ self.client_secret = client_secret or getenv("REDDIT_CLIENT_SECRET")
32
+ self.user_agent = user_agent or getenv("REDDIT_USER_AGENT", "RedditTools v1.0")
33
+ self.username = username or getenv("REDDIT_USERNAME")
34
+ self.password = password or getenv("REDDIT_PASSWORD")
35
+
36
+ self.reddit = None
37
+ # Check if we have all required credentials
38
+ if all([self.client_id, self.client_secret]):
39
+ # Initialize with read-only access if no user credentials
40
+ if not all([self.username, self.password]):
41
+ log_info("Initializing Reddit client with read-only access")
42
+ self.reddit = praw.Reddit(
43
+ client_id=self.client_id,
44
+ client_secret=self.client_secret,
45
+ user_agent=self.user_agent,
46
+ )
47
+ # Initialize with user authentication if credentials provided
48
+ else:
49
+ log_info(f"Initializing Reddit client with user authentication for u/{self.username}")
50
+ self.reddit = praw.Reddit(
51
+ client_id=self.client_id,
52
+ client_secret=self.client_secret,
53
+ user_agent=self.user_agent,
54
+ username=self.username,
55
+ password=self.password,
56
+ )
57
+ else:
58
+ logger.warning("Missing Reddit API credentials")
59
+
60
+ tools: List[Callable] = [
61
+ self.get_user_info,
62
+ self.get_top_posts,
63
+ self.get_subreddit_info,
64
+ self.get_trending_subreddits,
65
+ self.get_subreddit_stats,
66
+ self.create_post,
67
+ self.reply_to_post,
68
+ self.reply_to_comment,
69
+ ]
70
+
71
+ super().__init__(name="reddit", tools=tools, **kwargs)
72
+
73
+ def _check_user_auth(self) -> bool:
74
+ """
75
+ Check if user authentication is available for actions that require it.
76
+ Returns:
77
+ bool: True if user is authenticated, False otherwise
78
+ """
79
+ if not self.reddit:
80
+ logger.error("Reddit client not initialized")
81
+ return False
82
+
83
+ if not all([self.username, self.password]):
84
+ logger.error("User authentication required. Please provide username and password.")
85
+ return False
86
+
87
+ try:
88
+ # Verify authentication by checking if we can get the authenticated user
89
+ self.reddit.user.me()
90
+ return True
91
+ except Exception as e:
92
+ logger.error(f"Authentication error: {e}")
93
+ return False
94
+
95
+ def get_user_info(self, username: str) -> str:
96
+ """Get information about a Reddit user."""
97
+ if not self.reddit:
98
+ return "Please provide Reddit API credentials"
99
+
100
+ try:
101
+ log_info(f"Getting info for u/{username}")
102
+
103
+ user = self.reddit.redditor(username)
104
+ info: Dict[str, Union[str, int, bool, float]] = {
105
+ "name": user.name,
106
+ "comment_karma": user.comment_karma,
107
+ "link_karma": user.link_karma,
108
+ "is_mod": user.is_mod,
109
+ "is_gold": user.is_gold,
110
+ "is_employee": user.is_employee,
111
+ "created_utc": user.created_utc,
112
+ }
113
+
114
+ return json.dumps(info)
115
+
116
+ except Exception as e:
117
+ return f"Error getting user info: {e}"
118
+
119
+ def get_top_posts(self, subreddit: str, time_filter: str = "week", limit: int = 10) -> str:
120
+ """
121
+ Get top posts from a subreddit for a specific time period.
122
+ Args:
123
+ subreddit (str): Name of the subreddit.
124
+ time_filter (str): Time period to filter posts.
125
+ limit (int): Number of posts to fetch.
126
+ Returns:
127
+ str: JSON string containing top posts.
128
+ """
129
+ if not self.reddit:
130
+ return "Please provide Reddit API credentials"
131
+
132
+ try:
133
+ log_debug(f"Getting top posts from r/{subreddit}")
134
+ posts = self.reddit.subreddit(subreddit).top(time_filter=time_filter, limit=limit)
135
+ top_posts: List[Dict[str, Union[str, int, float]]] = [
136
+ {
137
+ "id": post.id,
138
+ "title": post.title,
139
+ "score": post.score,
140
+ "url": post.url,
141
+ "selftext": post.selftext,
142
+ "author": str(post.author),
143
+ "permalink": post.permalink,
144
+ "created_utc": post.created_utc,
145
+ "subreddit": str(post.subreddit),
146
+ "subreddit_name_prefixed": post.subreddit_name_prefixed,
147
+ }
148
+ for post in posts
149
+ ]
150
+ return json.dumps({"top_posts": top_posts})
151
+ except Exception as e:
152
+ return f"Error getting top posts: {e}"
153
+
154
+ def get_subreddit_info(self, subreddit_name: str) -> str:
155
+ """
156
+ Get information about a specific subreddit.
157
+ Args:
158
+ subreddit_name (str): Name of the subreddit.
159
+ Returns:
160
+ str: JSON string containing subreddit information.
161
+ """
162
+ if not self.reddit:
163
+ return "Please provide Reddit API credentials"
164
+
165
+ try:
166
+ log_info(f"Getting info for r/{subreddit_name}")
167
+
168
+ subreddit = self.reddit.subreddit(subreddit_name)
169
+ flairs = [flair["text"] for flair in subreddit.flair.link_templates]
170
+ info: Dict[str, Union[str, int, bool, float, List[str]]] = {
171
+ "display_name": subreddit.display_name,
172
+ "title": subreddit.title,
173
+ "description": subreddit.description,
174
+ "subscribers": subreddit.subscribers,
175
+ "created_utc": subreddit.created_utc,
176
+ "over18": subreddit.over18,
177
+ "available_flairs": flairs,
178
+ "public_description": subreddit.public_description,
179
+ "url": subreddit.url,
180
+ }
181
+
182
+ return json.dumps(info)
183
+
184
+ except Exception as e:
185
+ return f"Error getting subreddit info: {e}"
186
+
187
+ def get_trending_subreddits(self) -> str:
188
+ """Get currently trending subreddits."""
189
+ if not self.reddit:
190
+ return "Please provide Reddit API credentials"
191
+
192
+ try:
193
+ log_debug("Getting trending subreddits")
194
+ popular_subreddits = self.reddit.subreddits.popular(limit=5)
195
+ trending: List[str] = [subreddit.display_name for subreddit in popular_subreddits]
196
+ return json.dumps({"trending_subreddits": trending})
197
+ except Exception as e:
198
+ return f"Error getting trending subreddits: {e}"
199
+
200
+ def get_subreddit_stats(self, subreddit: str) -> str:
201
+ """
202
+ Get statistics about a subreddit.
203
+ Args:
204
+ subreddit (str): Name of the subreddit.
205
+ Returns:
206
+ str: JSON string containing subreddit statistics
207
+ """
208
+ if not self.reddit:
209
+ return "Please provide Reddit API credentials"
210
+
211
+ try:
212
+ log_debug(f"Getting stats for r/{subreddit}")
213
+ sub = self.reddit.subreddit(subreddit)
214
+ stats: Dict[str, Union[str, int, bool, float]] = {
215
+ "display_name": sub.display_name,
216
+ "subscribers": sub.subscribers,
217
+ "active_users": sub.active_user_count,
218
+ "description": sub.description,
219
+ "created_utc": sub.created_utc,
220
+ "over18": sub.over18,
221
+ "public_description": sub.public_description,
222
+ }
223
+ return json.dumps({"subreddit_stats": stats})
224
+ except Exception as e:
225
+ return f"Error getting subreddit stats: {e}"
226
+
227
+ def create_post(
228
+ self,
229
+ subreddit: str,
230
+ title: str,
231
+ content: str,
232
+ flair: Optional[str] = None,
233
+ is_self: bool = True,
234
+ ) -> str:
235
+ """
236
+ Create a new post in a subreddit.
237
+
238
+ Args:
239
+ subreddit (str): Name of the subreddit to post in.
240
+ title (str): Title of the post.
241
+ content (str): Content of the post (text for self posts, URL for link posts).
242
+ flair (Optional[str]): Flair to add to the post. Must be an available flair in the subreddit.
243
+ is_self (bool): Whether this is a self (text) post (True) or link post (False).
244
+ Returns:
245
+ str: JSON string containing the created post information.
246
+ """
247
+ if not self.reddit:
248
+ return "Please provide Reddit API credentials"
249
+
250
+ if not self._check_user_auth():
251
+ return "User authentication required for posting. Please provide username and password."
252
+
253
+ try:
254
+ log_info(f"Creating post in r/{subreddit}")
255
+
256
+ subreddit_obj = self.reddit.subreddit(subreddit)
257
+
258
+ if flair:
259
+ available_flairs = [f["text"] for f in subreddit_obj.flair.link_templates]
260
+ if flair not in available_flairs:
261
+ return f"Invalid flair. Available flairs: {', '.join(available_flairs)}"
262
+
263
+ if is_self:
264
+ submission = subreddit_obj.submit(
265
+ title=title,
266
+ selftext=content,
267
+ flair_id=flair,
268
+ )
269
+ else:
270
+ submission = subreddit_obj.submit(
271
+ title=title,
272
+ url=content,
273
+ flair_id=flair,
274
+ )
275
+ log_info(f"Post created: {submission.permalink}")
276
+
277
+ post_info: Dict[str, Union[str, int, float]] = {
278
+ "id": submission.id,
279
+ "title": submission.title,
280
+ "url": submission.url,
281
+ "permalink": submission.permalink,
282
+ "created_utc": submission.created_utc,
283
+ "author": str(submission.author),
284
+ "flair": submission.link_flair_text,
285
+ }
286
+
287
+ return json.dumps({"post": post_info})
288
+
289
+ except Exception as e:
290
+ return f"Error creating post: {e}"
291
+
292
+ def reply_to_post(self, post_id: str, content: str, subreddit: Optional[str] = None) -> str:
293
+ """
294
+ Post a reply to an existing Reddit post or comment.
295
+
296
+ Args:
297
+ post_id (str): The ID of the post or comment to reply to.
298
+ Can be a full URL, permalink, or just the ID.
299
+ content (str): The content of the reply.
300
+ subreddit (Optional[str]): The subreddit name if known.
301
+ This helps with error handling and validation.
302
+
303
+ Returns:
304
+ str: JSON string containing information about the created reply.
305
+ """
306
+ if not self.reddit:
307
+ logger.error("Reddit instance not initialized")
308
+ return "Please provide Reddit API credentials"
309
+
310
+ if not self._check_user_auth():
311
+ logger.error("User authentication failed")
312
+ return "User authentication required for posting replies. Please provide username and password."
313
+
314
+ try:
315
+ log_debug(f"Creating reply to post {post_id}")
316
+
317
+ # Clean up the post_id if it's a full URL or permalink
318
+ if "/" in post_id:
319
+ # Extract the actual ID from the URL/permalink
320
+ original_id = post_id
321
+ post_id = post_id.split("/")[-1]
322
+ log_debug(f"Extracted post ID {post_id} from {original_id}")
323
+
324
+ # Verify post exists
325
+ if not self._check_post_exists(post_id):
326
+ error_msg = f"Post with ID {post_id} does not exist or is not accessible"
327
+ logger.error(error_msg)
328
+ return error_msg
329
+
330
+ # Get the submission object
331
+ submission = self.reddit.submission(id=post_id)
332
+
333
+ log_debug(
334
+ f"Post details: Title: {submission.title}, Author: {submission.author}, Subreddit: {submission.subreddit.display_name}"
335
+ )
336
+
337
+ # If subreddit was provided, verify we're in the right place
338
+ if subreddit and submission.subreddit.display_name.lower() != subreddit.lower():
339
+ error_msg = f"Error: Post ID belongs to r/{submission.subreddit.display_name}, not r/{subreddit}"
340
+ logger.error(error_msg)
341
+ return error_msg
342
+
343
+ # Create the reply
344
+ log_debug(f"Attempting to post reply with content length: {len(content)}")
345
+ reply = submission.reply(body=content)
346
+
347
+ # Prepare the response information
348
+ reply_info: Dict[str, Union[str, int, float]] = {
349
+ "id": reply.id,
350
+ "body": reply.body,
351
+ "score": reply.score,
352
+ "permalink": reply.permalink,
353
+ "created_utc": reply.created_utc,
354
+ "author": str(reply.author),
355
+ "parent_id": reply.parent_id,
356
+ "submission_id": submission.id,
357
+ "subreddit": str(reply.subreddit),
358
+ }
359
+
360
+ log_debug(f"Reply created successfully: {reply.permalink}")
361
+ return json.dumps({"reply": reply_info})
362
+
363
+ except praw.exceptions.RedditAPIException as api_error:
364
+ # Handle specific Reddit API errors
365
+ error_messages = [f"{error.error_type}: {error.message}" for error in api_error.items]
366
+ error_msg = f"Reddit API Error: {'; '.join(error_messages)}"
367
+ logger.error(error_msg)
368
+ return error_msg
369
+
370
+ except Exception as e:
371
+ error_msg = f"Error creating reply: {str(e)}"
372
+ logger.error(error_msg)
373
+ return error_msg
374
+
375
+ def reply_to_comment(self, comment_id: str, content: str, subreddit: Optional[str] = None) -> str:
376
+ """
377
+ Post a reply to an existing Reddit comment.
378
+
379
+ Args:
380
+ comment_id (str): The ID of the comment to reply to.
381
+ Can be a full URL, permalink, or just the ID.
382
+ content (str): The content of the reply.
383
+ subreddit (Optional[str]): The subreddit name if known.
384
+ This helps with error handling and validation.
385
+
386
+ Returns:
387
+ str: JSON string containing information about the created reply.
388
+ """
389
+ if not self.reddit:
390
+ logger.error("Reddit instance not initialized")
391
+ return "Please provide Reddit API credentials"
392
+
393
+ if not self._check_user_auth():
394
+ logger.error("User authentication failed")
395
+ return "User authentication required for posting replies. Please provide username and password."
396
+
397
+ try:
398
+ log_debug(f"Creating reply to comment {comment_id}")
399
+
400
+ # Clean up the comment_id if it's a full URL or permalink
401
+ if "/" in comment_id:
402
+ original_id = comment_id
403
+ comment_id = comment_id.split("/")[-1]
404
+ log_info(f"Extracted comment ID {comment_id} from {original_id}")
405
+
406
+ # Get the comment object
407
+ comment = self.reddit.comment(id=comment_id)
408
+
409
+ log_debug(f"Comment details: Author: {comment.author}, Subreddit: {comment.subreddit.display_name}")
410
+
411
+ # If subreddit was provided, verify we're in the right place
412
+ if subreddit and comment.subreddit.display_name.lower() != subreddit.lower():
413
+ error_msg = f"Error: Comment ID belongs to r/{comment.subreddit.display_name}, not r/{subreddit}"
414
+ logger.error(error_msg)
415
+ return error_msg
416
+
417
+ # Create the reply
418
+ log_debug(f"Attempting to post reply with content length: {len(content)}")
419
+ reply = comment.reply(body=content)
420
+
421
+ # Prepare the response information
422
+ reply_info: Dict[str, Union[str, int, float]] = {
423
+ "id": reply.id,
424
+ "body": reply.body,
425
+ "score": reply.score,
426
+ "permalink": reply.permalink,
427
+ "created_utc": reply.created_utc,
428
+ "author": str(reply.author),
429
+ "parent_id": reply.parent_id,
430
+ "submission_id": comment.submission.id,
431
+ "subreddit": str(reply.subreddit),
432
+ }
433
+
434
+ log_debug(f"Reply created successfully: {reply.permalink}")
435
+ return json.dumps({"reply": reply_info})
436
+
437
+ except praw.exceptions.RedditAPIException as api_error:
438
+ # Handle specific Reddit API errors
439
+ error_messages = [f"{error.error_type}: {error.message}" for error in api_error.items]
440
+ error_msg = f"Reddit API Error: {'; '.join(error_messages)}"
441
+ logger.error(error_msg)
442
+ return error_msg
443
+
444
+ except Exception as e:
445
+ error_msg = f"Error creating reply: {str(e)}"
446
+ logger.error(error_msg)
447
+ return error_msg
448
+
449
+ def _check_post_exists(self, post_id: str) -> bool:
450
+ """
451
+ Verify that a post exists and is accessible.
452
+
453
+ Args:
454
+ post_id (str): The ID of the post to check
455
+
456
+ Returns:
457
+ bool: True if post exists and is accessible, False otherwise
458
+ """
459
+ try:
460
+ submission = self.reddit.submission(id=post_id)
461
+ # Try to access some attributes to verify the post exists
462
+ _ = submission.title
463
+ _ = submission.author
464
+ return True
465
+ except Exception as e:
466
+ logger.error(f"Error checking post existence: {str(e)}")
467
+ return False
@@ -0,0 +1,117 @@
1
+ from os import getenv
2
+ from pathlib import Path
3
+ from typing import Any, Iterable, Iterator, List, Optional, Tuple, Union
4
+ from urllib.parse import urlparse
5
+ from uuid import uuid4
6
+
7
+ from agno.agent import Agent
8
+ from agno.media import Image, Video
9
+ from agno.team.team import Team
10
+ from agno.tools import Toolkit
11
+ from agno.tools.function import ToolResult
12
+ from agno.utils.log import logger
13
+
14
+ try:
15
+ import replicate
16
+ from replicate.helpers import FileOutput
17
+ except ImportError:
18
+ raise ImportError("`replicate` not installed. Please install using `pip install replicate`.")
19
+
20
+
21
+ class ReplicateTools(Toolkit):
22
+ def __init__(
23
+ self,
24
+ api_key: Optional[str] = None,
25
+ model: str = "minimax/video-01",
26
+ enable_generate_media: bool = True,
27
+ all: bool = False,
28
+ **kwargs,
29
+ ):
30
+ self.api_key = api_key or getenv("REPLICATE_API_KEY")
31
+ if not self.api_key:
32
+ logger.error("REPLICATE_API_KEY not set. Please set the REPLICATE_API_KEY environment variable.")
33
+ self.model = model
34
+
35
+ tools: List[Any] = []
36
+ if all or enable_generate_media:
37
+ tools.append(self.generate_media)
38
+
39
+ super().__init__(name="replicate_toolkit", tools=tools, **kwargs)
40
+
41
+ def generate_media(self, agent: Union[Agent, Team], prompt: str) -> ToolResult:
42
+ """
43
+ Use this function to generate an image or a video using a replicate model.
44
+ Args:
45
+ prompt (str): A text description of the content.
46
+ Returns:
47
+ ToolResult: A ToolResult containing the generated media or error message.
48
+ """
49
+ if not self.api_key:
50
+ logger.error("API key is not set. Please provide a valid API key.")
51
+ return ToolResult(content="API key is not set.")
52
+
53
+ try:
54
+ outputs = replicate.run(ref=self.model, input={"prompt": prompt})
55
+ if isinstance(outputs, FileOutput):
56
+ outputs = [outputs]
57
+ elif isinstance(outputs, (Iterable, Iterator)) and not isinstance(outputs, str):
58
+ outputs = list(outputs)
59
+ else:
60
+ logger.error(f"Unexpected output type: {type(outputs)}")
61
+ return ToolResult(content=f"Unexpected output type: {type(outputs)}")
62
+
63
+ images = []
64
+ videos = []
65
+ results = []
66
+
67
+ for output in outputs:
68
+ if not isinstance(output, FileOutput):
69
+ logger.error(f"Unexpected output type: {type(output)}")
70
+ return ToolResult(content=f"Unexpected output type: {type(output)}")
71
+
72
+ result_msg, media_artifact = self._parse_output(output)
73
+ results.append(result_msg)
74
+
75
+ if isinstance(media_artifact, Image):
76
+ images.append(media_artifact)
77
+ elif isinstance(media_artifact, Video):
78
+ videos.append(media_artifact)
79
+
80
+ content = "\n".join(results)
81
+ return ToolResult(
82
+ content=content,
83
+ images=images if images else None,
84
+ videos=videos if videos else None,
85
+ )
86
+ except Exception as e:
87
+ logger.error(f"Failed to generate media: {e}")
88
+ return ToolResult(content=f"Error: {e}")
89
+
90
+ def _parse_output(self, output: FileOutput) -> Tuple[str, Union[Image, Video]]:
91
+ """
92
+ Parse the outputs from the replicate model.
93
+ """
94
+ # Parse the URL to extract the file extension
95
+ parsed_url = urlparse(output.url)
96
+ path = parsed_url.path
97
+ ext = Path(path).suffix.lower()
98
+
99
+ # Define supported extensions
100
+ image_extensions = {".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".webp"}
101
+ video_extensions = {".mp4", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".webm"}
102
+
103
+ media_id = str(uuid4())
104
+ artifact: Union[Image, Video]
105
+ media_type: str
106
+
107
+ if ext in image_extensions:
108
+ artifact = Image(id=media_id, url=output.url)
109
+ media_type = "image"
110
+ elif ext in video_extensions:
111
+ artifact = Video(id=media_id, url=output.url)
112
+ media_type = "video"
113
+ else:
114
+ logger.error(f"Unsupported media type with extension '{ext}' for URL: {output.url}")
115
+ raise ValueError(f"Unsupported media type with extension '{ext}'.")
116
+
117
+ return f"{media_type.capitalize()} generated successfully at {output.url}", artifact
agno/tools/resend.py ADDED
@@ -0,0 +1,62 @@
1
+ from os import getenv
2
+ from typing import Any, List, Optional
3
+
4
+ from agno.tools import Toolkit
5
+ from agno.utils.log import log_info, logger
6
+
7
+ try:
8
+ import resend # type: ignore
9
+ except ImportError:
10
+ raise ImportError("`resend` not installed. Please install using `pip install resend`.")
11
+
12
+
13
+ class ResendTools(Toolkit):
14
+ def __init__(
15
+ self,
16
+ api_key: Optional[str] = None,
17
+ from_email: Optional[str] = None,
18
+ enable_send_email: bool = True,
19
+ all: bool = False,
20
+ **kwargs,
21
+ ):
22
+ self.from_email = from_email
23
+ self.api_key = api_key or getenv("RESEND_API_KEY")
24
+ if not self.api_key:
25
+ logger.error("No Resend API key provided")
26
+
27
+ tools: List[Any] = []
28
+ if all or enable_send_email:
29
+ tools.append(self.send_email)
30
+
31
+ super().__init__(name="resend_tools", tools=tools, **kwargs)
32
+
33
+ def send_email(self, to_email: str, subject: str, body: str) -> str:
34
+ """Send an email using the Resend API. Returns if the email was sent successfully or an error message.
35
+
36
+ :to_email: The email address to send the email to.
37
+ :subject: The subject of the email.
38
+ :body: The body of the email.
39
+ :return: A string indicating if the email was sent successfully or an error message.
40
+ """
41
+
42
+ if not self.api_key:
43
+ return "Please provide an API key"
44
+ if not to_email:
45
+ return "Please provide an email address to send the email to"
46
+
47
+ log_info(f"Sending email to: {to_email}")
48
+
49
+ resend.api_key = self.api_key
50
+ try:
51
+ params = {
52
+ "from": self.from_email,
53
+ "to": to_email,
54
+ "subject": subject,
55
+ "html": body,
56
+ }
57
+
58
+ resend.Emails.send(params)
59
+ return f"Email sent to {to_email} successfully."
60
+ except Exception as e:
61
+ logger.error(f"Failed to send email {e}")
62
+ return f"Error: {e}"