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/redshift.py ADDED
@@ -0,0 +1,406 @@
1
+ import csv
2
+ from os import getenv
3
+ from typing import Any, Dict, List, Optional
4
+
5
+ try:
6
+ import redshift_connector
7
+ from redshift_connector import Connection
8
+ except ImportError:
9
+ raise ImportError("`redshift_connector` not installed. Please install using `pip install redshift-connector`.")
10
+
11
+ from agno.tools import Toolkit
12
+ from agno.utils.log import log_debug, log_error, log_info
13
+
14
+
15
+ class RedshiftTools(Toolkit):
16
+ """
17
+ A toolkit for interacting with Amazon Redshift databases.
18
+
19
+ Supports these authentication methods:
20
+ - Standard username and password authentication
21
+ - IAM authentication with AWS profile
22
+ - IAM authentication with AWS credentials
23
+
24
+ Args:
25
+ host (Optional[str]): Redshift cluster endpoint hostname. Falls back to REDSHIFT_HOST env var.
26
+ port (int): Redshift cluster port number. Default is 5439.
27
+ database (Optional[str]): Database name to connect to. Falls back to REDSHIFT_DATABASE env var.
28
+ user (Optional[str]): Username for standard authentication.
29
+ password (Optional[str]): Password for standard authentication.
30
+ iam (bool): Enable IAM authentication. Default is False.
31
+ cluster_identifier (Optional[str]): Redshift cluster identifier for IAM auth with provisioned clusters. Falls back to REDSHIFT_CLUSTER_IDENTIFIER env var.
32
+ region (Optional[str]): AWS region for IAM credential retrieval. Falls back to AWS_REGION or AWS_DEFAULT_REGION env vars.
33
+ db_user (Optional[str]): Database user for IAM auth with provisioned clusters. Falls back to REDSHIFT_DB_USER env var.
34
+ access_key_id (Optional[str]): AWS access key ID for IAM auth. Falls back to AWS_ACCESS_KEY_ID env var.
35
+ secret_access_key (Optional[str]): AWS secret access key for IAM auth. Falls back to AWS_SECRET_ACCESS_KEY env var.
36
+ session_token (Optional[str]): AWS session token for temporary credentials. Falls back to AWS_SESSION_TOKEN env var.
37
+ profile (Optional[str]): AWS profile name for IAM auth. Falls back to AWS_PROFILE env var.
38
+ ssl (bool): Enable SSL connection. Default is True.
39
+ table_schema (str): Default schema for table operations. Default is "public".
40
+ """
41
+
42
+ _requires_connect: bool = True
43
+
44
+ def __init__(
45
+ self,
46
+ # Connection parameters
47
+ host: Optional[str] = None,
48
+ port: int = 5439,
49
+ database: Optional[str] = None,
50
+ # Standard authentication (username/password)
51
+ user: Optional[str] = None,
52
+ password: Optional[str] = None,
53
+ # IAM Authentication
54
+ iam: bool = False,
55
+ cluster_identifier: Optional[str] = None,
56
+ region: Optional[str] = None,
57
+ db_user: Optional[str] = None,
58
+ # AWS Credentials (for IAM auth)
59
+ access_key_id: Optional[str] = None,
60
+ secret_access_key: Optional[str] = None,
61
+ session_token: Optional[str] = None,
62
+ profile: Optional[str] = None,
63
+ # Connection settings
64
+ ssl: bool = True,
65
+ table_schema: str = "public",
66
+ **kwargs,
67
+ ):
68
+ # Connection parameters
69
+ self.host: Optional[str] = host or getenv("REDSHIFT_HOST")
70
+ self.port: int = port
71
+ self.database: Optional[str] = database or getenv("REDSHIFT_DATABASE")
72
+
73
+ # Standard authentication
74
+ self.user: Optional[str] = user
75
+ self.password: Optional[str] = password
76
+
77
+ # IAM authentication parameters
78
+ self.iam: bool = iam
79
+ self.cluster_identifier: Optional[str] = cluster_identifier or getenv("REDSHIFT_CLUSTER_IDENTIFIER")
80
+ self.region: Optional[str] = region or getenv("AWS_REGION") or getenv("AWS_DEFAULT_REGION")
81
+ self.db_user: Optional[str] = db_user or getenv("REDSHIFT_DB_USER")
82
+
83
+ # AWS credentials
84
+ self.access_key_id: Optional[str] = access_key_id or getenv("AWS_ACCESS_KEY_ID")
85
+ self.secret_access_key: Optional[str] = secret_access_key or getenv("AWS_SECRET_ACCESS_KEY")
86
+ self.session_token: Optional[str] = session_token or getenv("AWS_SESSION_TOKEN")
87
+ self.profile: Optional[str] = profile or getenv("AWS_PROFILE")
88
+
89
+ # Connection settings
90
+ self.ssl: bool = ssl
91
+ self.table_schema: str = table_schema
92
+
93
+ # Connection instance
94
+ self._connection: Optional[Connection] = None
95
+
96
+ tools: List[Any] = [
97
+ self.show_tables,
98
+ self.describe_table,
99
+ self.summarize_table,
100
+ self.inspect_query,
101
+ self.run_query,
102
+ self.export_table_to_path,
103
+ ]
104
+
105
+ super().__init__(name="redshift_tools", tools=tools, **kwargs)
106
+
107
+ def connect(self) -> Connection:
108
+ """
109
+ Establish a connection to the Redshift database.
110
+
111
+ Returns:
112
+ The database connection object.
113
+
114
+ Raises:
115
+ redshift_connector.Error: If connection fails.
116
+ """
117
+ if self._connection is not None:
118
+ log_debug("Connection already established, reusing existing connection")
119
+ return self._connection
120
+
121
+ log_info("Establishing connection to Redshift")
122
+ self._connection = redshift_connector.connect(**self._get_connection_kwargs())
123
+ return self._connection
124
+
125
+ def close(self) -> None:
126
+ """
127
+ Close the database connection if it exists.
128
+ """
129
+ if self._connection is not None:
130
+ log_info("Closing Redshift connection")
131
+ try:
132
+ self._connection.close()
133
+ except Exception:
134
+ pass # Connection might already be closed
135
+ self._connection = None
136
+
137
+ @property
138
+ def is_connected(self) -> bool:
139
+ """Check if a connection is currently established."""
140
+ return self._connection is not None
141
+
142
+ def _ensure_connection(self) -> Connection:
143
+ """
144
+ Ensure a connection exists, creating one if necessary.
145
+
146
+ Returns:
147
+ The database connection object.
148
+ """
149
+ if self._connection is None:
150
+ return self.connect()
151
+ return self._connection
152
+
153
+ def _get_connection_kwargs(self) -> Dict[str, Any]:
154
+ """Build connection kwargs from instance."""
155
+ connection_kwargs: Dict[str, Any] = {}
156
+
157
+ # Common connection parameters
158
+ if self.host:
159
+ connection_kwargs["host"] = self.host
160
+ if self.port:
161
+ connection_kwargs["port"] = self.port
162
+ if self.database:
163
+ connection_kwargs["database"] = self.database
164
+ connection_kwargs["ssl"] = self.ssl
165
+
166
+ # IAM Authentication
167
+ if self.iam:
168
+ connection_kwargs["iam"] = True
169
+
170
+ # For provisioned clusters (not serverless)
171
+ if self.cluster_identifier:
172
+ connection_kwargs["cluster_identifier"] = self.cluster_identifier
173
+ # db_user required for provisioned clusters with IAM
174
+ if self.db_user:
175
+ connection_kwargs["db_user"] = self.db_user
176
+
177
+ # Region for IAM credential retrieval
178
+ if self.region:
179
+ connection_kwargs["region"] = self.region
180
+
181
+ # AWS credentials - either profile or explicit
182
+ if self.profile:
183
+ connection_kwargs["profile"] = self.profile
184
+ else:
185
+ # Explicit AWS credentials
186
+ if self.access_key_id:
187
+ connection_kwargs["access_key_id"] = self.access_key_id
188
+ if self.secret_access_key:
189
+ connection_kwargs["secret_access_key"] = self.secret_access_key
190
+ if self.session_token:
191
+ connection_kwargs["session_token"] = self.session_token
192
+
193
+ else:
194
+ # Standard username/password authentication
195
+ if self.user:
196
+ connection_kwargs["user"] = self.user
197
+ if self.password:
198
+ connection_kwargs["password"] = self.password
199
+
200
+ return connection_kwargs
201
+
202
+ def _execute_query(self, query: str, params: Optional[tuple] = None) -> str:
203
+ try:
204
+ connection = self._ensure_connection()
205
+ with connection.cursor() as cursor:
206
+ log_debug("Running Redshift query")
207
+ cursor.execute(query, params)
208
+
209
+ if cursor.description is None:
210
+ return "Query executed successfully."
211
+
212
+ columns = [desc[0] for desc in cursor.description]
213
+ rows = cursor.fetchall()
214
+
215
+ if not rows:
216
+ return f"Query returned no results.\nColumns: {', '.join(columns)}"
217
+
218
+ header = ",".join(columns)
219
+ data_rows = [",".join(map(str, row)) for row in rows]
220
+ return f"{header}\n" + "\n".join(data_rows)
221
+
222
+ except redshift_connector.Error as e:
223
+ log_error(f"Database error: {e}")
224
+ if self._connection:
225
+ try:
226
+ self._connection.rollback()
227
+ except Exception:
228
+ pass # Connection might be closed
229
+ return f"Error executing query: {e}"
230
+ except Exception as e:
231
+ log_error(f"An unexpected error occurred: {e}")
232
+ return f"An unexpected error occurred: {e}"
233
+
234
+ def show_tables(self) -> str:
235
+ """Lists all tables in the configured schema."""
236
+
237
+ stmt = "SELECT table_name FROM information_schema.tables WHERE table_schema = %s;"
238
+ return self._execute_query(stmt, (self.table_schema,))
239
+
240
+ def describe_table(self, table: str) -> str:
241
+ """
242
+ Provides the schema (column name, data type, is nullable) for a given table.
243
+
244
+ Args:
245
+ table: The name of the table to describe.
246
+
247
+ Returns:
248
+ A string describing the table's columns and data types.
249
+ """
250
+ stmt = """
251
+ SELECT column_name, data_type, is_nullable
252
+ FROM information_schema.columns
253
+ WHERE table_schema = %s AND table_name = %s;
254
+ """
255
+ return self._execute_query(stmt, (self.table_schema, table))
256
+
257
+ def summarize_table(self, table: str) -> str:
258
+ """
259
+ Computes and returns key summary statistics for a table's columns.
260
+
261
+ Args:
262
+ table: The name of the table to summarize.
263
+
264
+ Returns:
265
+ A string containing a summary of the table.
266
+ """
267
+ try:
268
+ connection = self._ensure_connection()
269
+ with connection.cursor() as cursor:
270
+ # First, get column information using a parameterized query
271
+ schema_query = """
272
+ SELECT column_name, data_type
273
+ FROM information_schema.columns
274
+ WHERE table_schema = %s AND table_name = %s;
275
+ """
276
+ cursor.execute(schema_query, (self.table_schema, table))
277
+ columns = cursor.fetchall()
278
+ if not columns:
279
+ return f"Error: Table '{table}' not found in schema '{self.table_schema}'."
280
+
281
+ summary_parts = [f"Summary for table: {table}\n"]
282
+
283
+ # Redshift uses schema.table format for fully qualified names
284
+ full_table_name = f'"{self.table_schema}"."{table}"'
285
+
286
+ for col in columns:
287
+ col_name = col[0]
288
+ data_type = col[1]
289
+
290
+ query = None
291
+ if any(
292
+ t in data_type.lower()
293
+ for t in [
294
+ "integer",
295
+ "int",
296
+ "bigint",
297
+ "smallint",
298
+ "numeric",
299
+ "decimal",
300
+ "real",
301
+ "double precision",
302
+ "float",
303
+ ]
304
+ ):
305
+ query = f"""
306
+ SELECT
307
+ COUNT(*) AS total_rows,
308
+ COUNT("{col_name}") AS non_null_rows,
309
+ MIN("{col_name}") AS min,
310
+ MAX("{col_name}") AS max,
311
+ AVG("{col_name}") AS average,
312
+ STDDEV("{col_name}") AS std_deviation
313
+ FROM {full_table_name};
314
+ """
315
+ elif any(t in data_type.lower() for t in ["char", "varchar", "text", "uuid"]):
316
+ query = f"""
317
+ SELECT
318
+ COUNT(*) AS total_rows,
319
+ COUNT("{col_name}") AS non_null_rows,
320
+ COUNT(DISTINCT "{col_name}") AS unique_values,
321
+ AVG(LEN("{col_name}")) as avg_length
322
+ FROM {full_table_name};
323
+ """
324
+
325
+ if query:
326
+ cursor.execute(query)
327
+ stats = cursor.fetchone()
328
+ summary_parts.append(f"\n--- Column: {col_name} (Type: {data_type}) ---")
329
+ if stats is not None:
330
+ stats_dict = dict(zip([desc[0] for desc in cursor.description], stats))
331
+ for key, value in stats_dict.items():
332
+ val_str = (
333
+ f"{value:.2f}" if isinstance(value, float) and value is not None else str(value)
334
+ )
335
+ summary_parts.append(f" {key}: {val_str}")
336
+ else:
337
+ summary_parts.append(" No statistics available")
338
+
339
+ return "\n".join(summary_parts)
340
+
341
+ except redshift_connector.Error as e:
342
+ return f"Error summarizing table: {e}"
343
+
344
+ def inspect_query(self, query: str) -> str:
345
+ """
346
+ Shows the execution plan for a SQL query (using EXPLAIN).
347
+
348
+ Args:
349
+ query: The SQL query to inspect.
350
+
351
+ Returns:
352
+ The query's execution plan.
353
+ """
354
+ return self._execute_query(f"EXPLAIN {query}")
355
+
356
+ def export_table_to_path(self, table: str, path: str) -> str:
357
+ """
358
+ Exports a table's data to a local CSV file.
359
+
360
+ Args:
361
+ table: The name of the table to export.
362
+ path: The local file path to save the file.
363
+
364
+ Returns:
365
+ A confirmation message with the file path.
366
+ """
367
+ log_debug(f"Exporting table {table} to {path}")
368
+
369
+ full_table_name = f'"{self.table_schema}"."{table}"'
370
+ stmt = f"SELECT * FROM {full_table_name};"
371
+
372
+ try:
373
+ connection = self._ensure_connection()
374
+ with connection.cursor() as cursor:
375
+ cursor.execute(stmt)
376
+
377
+ if cursor.description is None:
378
+ return f"Error: Query returned no description for table '{table}'."
379
+
380
+ columns = [desc[0] for desc in cursor.description]
381
+
382
+ with open(path, "w", newline="", encoding="utf-8") as f:
383
+ writer = csv.writer(f)
384
+ writer.writerow(columns)
385
+ writer.writerows(cursor)
386
+
387
+ return f"Successfully exported table '{table}' to '{path}'."
388
+ except (redshift_connector.Error, IOError) as e:
389
+ if self._connection:
390
+ try:
391
+ self._connection.rollback()
392
+ except Exception:
393
+ pass # Connection might be closed
394
+ return f"Error exporting table: {e}"
395
+
396
+ def run_query(self, query: str) -> str:
397
+ """
398
+ Runs a read-only SQL query and returns the result.
399
+
400
+ Args:
401
+ query: The SQL query to run.
402
+
403
+ Returns:
404
+ The query result as a formatted string.
405
+ """
406
+ return self._execute_query(query)
agno/tools/replicate.py CHANGED
@@ -1,12 +1,14 @@
1
- import os
2
1
  from os import getenv
3
- from typing import Optional
2
+ from pathlib import Path
3
+ from typing import Any, Iterable, Iterator, List, Optional, Tuple, Union
4
4
  from urllib.parse import urlparse
5
5
  from uuid import uuid4
6
6
 
7
7
  from agno.agent import Agent
8
- from agno.media import ImageArtifact, VideoArtifact
8
+ from agno.media import Image, Video
9
+ from agno.team.team import Team
9
10
  from agno.tools import Toolkit
11
+ from agno.tools.function import ToolResult
10
12
  from agno.utils.log import logger
11
13
 
12
14
  try:
@@ -21,54 +23,95 @@ class ReplicateTools(Toolkit):
21
23
  self,
22
24
  api_key: Optional[str] = None,
23
25
  model: str = "minimax/video-01",
26
+ enable_generate_media: bool = True,
27
+ all: bool = False,
28
+ **kwargs,
24
29
  ):
25
- super().__init__(name="replicate_toolkit")
26
- self.api_key = api_key or getenv("REPLICATE_API_TOKEN")
30
+ self.api_key = api_key or getenv("REPLICATE_API_KEY")
27
31
  if not self.api_key:
28
- logger.error("REPLICATE_API_TOKEN not set. Please set the REPLICATE_API_TOKEN environment variable.")
32
+ logger.error("REPLICATE_API_KEY not set. Please set the REPLICATE_API_KEY environment variable.")
29
33
  self.model = model
30
- self.register(self.generate_media)
31
34
 
32
- def generate_media(self, agent: Agent, prompt: str) -> str:
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:
33
42
  """
34
43
  Use this function to generate an image or a video using a replicate model.
35
44
  Args:
36
45
  prompt (str): A text description of the content.
37
46
  Returns:
38
- str: Return a URI to the generated video or image.
47
+ ToolResult: A ToolResult containing the generated media or error message.
39
48
  """
40
- output: FileOutput = replicate.run(ref=self.model, input={"prompt": prompt})
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)
41
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
+ """
42
94
  # Parse the URL to extract the file extension
43
95
  parsed_url = urlparse(output.url)
44
96
  path = parsed_url.path
45
- _, ext = os.path.splitext(path)
46
- ext = ext.lower()
97
+ ext = Path(path).suffix.lower()
47
98
 
48
99
  # Define supported extensions
49
100
  image_extensions = {".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".webp"}
50
101
  video_extensions = {".mp4", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".webm"}
51
102
 
52
103
  media_id = str(uuid4())
104
+ artifact: Union[Image, Video]
105
+ media_type: str
53
106
 
54
107
  if ext in image_extensions:
55
- agent.add_image(
56
- ImageArtifact(
57
- id=media_id,
58
- url=output.url,
59
- )
60
- )
108
+ artifact = Image(id=media_id, url=output.url)
61
109
  media_type = "image"
62
110
  elif ext in video_extensions:
63
- agent.add_video(
64
- VideoArtifact(
65
- id=media_id,
66
- url=output.url,
67
- )
68
- )
111
+ artifact = Video(id=media_id, url=output.url)
69
112
  media_type = "video"
70
113
  else:
71
114
  logger.error(f"Unsupported media type with extension '{ext}' for URL: {output.url}")
72
- return f"Unsupported media type with extension '{ext}'."
115
+ raise ValueError(f"Unsupported media type with extension '{ext}'.")
73
116
 
74
- return f"{media_type.capitalize()} generated successfully at {output.url}"
117
+ return f"{media_type.capitalize()} generated successfully at {output.url}", artifact
agno/tools/resend.py CHANGED
@@ -1,8 +1,8 @@
1
1
  from os import getenv
2
- from typing import Optional
2
+ from typing import Any, List, Optional
3
3
 
4
4
  from agno.tools import Toolkit
5
- from agno.utils.log import logger
5
+ from agno.utils.log import log_info, logger
6
6
 
7
7
  try:
8
8
  import resend # type: ignore
@@ -15,15 +15,20 @@ class ResendTools(Toolkit):
15
15
  self,
16
16
  api_key: Optional[str] = None,
17
17
  from_email: Optional[str] = None,
18
+ enable_send_email: bool = True,
19
+ all: bool = False,
20
+ **kwargs,
18
21
  ):
19
- super().__init__(name="resend_tools")
20
-
21
22
  self.from_email = from_email
22
23
  self.api_key = api_key or getenv("RESEND_API_KEY")
23
24
  if not self.api_key:
24
25
  logger.error("No Resend API key provided")
25
26
 
26
- self.register(self.send_email)
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)
27
32
 
28
33
  def send_email(self, to_email: str, subject: str, body: str) -> str:
29
34
  """Send an email using the Resend API. Returns if the email was sent successfully or an error message.
@@ -39,7 +44,7 @@ class ResendTools(Toolkit):
39
44
  if not to_email:
40
45
  return "Please provide an email address to send the email to"
41
46
 
42
- logger.info(f"Sending email to: {to_email}")
47
+ log_info(f"Sending email to: {to_email}")
43
48
 
44
49
  resend.api_key = self.api_key
45
50
  try: