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/whatsapp.py ADDED
@@ -0,0 +1,286 @@
1
+ from os import getenv
2
+ from typing import Any, Dict, List, Optional
3
+
4
+ import httpx
5
+
6
+ from agno.tools import Toolkit
7
+ from agno.utils.log import logger
8
+
9
+
10
+ class WhatsAppTools(Toolkit):
11
+ """WhatsApp Business API toolkit for sending messages."""
12
+
13
+ base_url = "https://graph.facebook.com"
14
+
15
+ def __init__(
16
+ self,
17
+ access_token: Optional[str] = None,
18
+ phone_number_id: Optional[str] = None,
19
+ version: Optional[str] = None,
20
+ recipient_waid: Optional[str] = None,
21
+ async_mode: bool = False,
22
+ ):
23
+ """Initialize WhatsApp toolkit.
24
+
25
+ Args:
26
+ access_token: WhatsApp Business API access token
27
+ phone_number_id: WhatsApp Business Account phone number ID
28
+ version: API version to use
29
+ recipient_waid: Default recipient WhatsApp ID (optional)
30
+ async_mode: Whether to use async methods (default: False)
31
+ """
32
+ # Core credentials
33
+ self.access_token = access_token or getenv("WHATSAPP_ACCESS_TOKEN")
34
+ if not self.access_token:
35
+ logger.error("WHATSAPP_ACCESS_TOKEN not set. Please set the WHATSAPP_ACCESS_TOKEN environment variable.")
36
+
37
+ self.phone_number_id = phone_number_id or getenv("WHATSAPP_PHONE_NUMBER_ID")
38
+ if not self.phone_number_id:
39
+ logger.error(
40
+ "WHATSAPP_PHONE_NUMBER_ID not set. Please set the WHATSAPP_PHONE_NUMBER_ID environment variable."
41
+ )
42
+
43
+ # Optional default recipient
44
+ self.default_recipient = recipient_waid or getenv("WHATSAPP_RECIPIENT_WAID")
45
+
46
+ # API version and mode
47
+ self.version = version or getenv("WHATSAPP_VERSION", "v22.0")
48
+ self.async_mode = async_mode
49
+
50
+ tools: List[Any] = []
51
+ if self.async_mode:
52
+ tools.append(self.send_text_message_async)
53
+ tools.append(self.send_template_message_async)
54
+ else:
55
+ tools.append(self.send_text_message_sync)
56
+ tools.append(self.send_template_message_sync)
57
+
58
+ super().__init__(name="whatsapp", tools=tools)
59
+
60
+ def _get_headers(self) -> Dict[str, str]:
61
+ """Get headers for API requests."""
62
+ return {"Authorization": f"Bearer {self.access_token}", "Content-Type": "application/json"}
63
+
64
+ def _get_messages_url(self) -> str:
65
+ """Get the messages endpoint URL."""
66
+ return f"{self.base_url}/{self.version}/{self.phone_number_id}/messages"
67
+
68
+ async def _send_message_async(self, data: Dict[str, Any]) -> Dict[str, Any]:
69
+ """Send a message asynchronously using the WhatsApp API.
70
+
71
+ Args:
72
+ data: Message data to send
73
+
74
+ Returns:
75
+ API response as dictionary
76
+ """
77
+ url = self._get_messages_url()
78
+ headers = self._get_headers()
79
+
80
+ logger.debug(f"Sending WhatsApp request to URL: {url}")
81
+
82
+ async with httpx.AsyncClient() as client:
83
+ response = await client.post(url, headers=headers, json=data)
84
+
85
+ response.raise_for_status()
86
+ return response.json()
87
+
88
+ def _send_message_sync(self, data: Dict[str, Any]) -> Dict[str, Any]:
89
+ """Send a message synchronously using the WhatsApp API.
90
+
91
+ Args:
92
+ data: Message data to send
93
+
94
+ Returns:
95
+ API response as dictionary
96
+ """
97
+ url = self._get_messages_url()
98
+ headers = self._get_headers()
99
+
100
+ logger.debug(f"Sending WhatsApp request to URL: {url}")
101
+ response = httpx.post(url, headers=headers, json=data)
102
+
103
+ response.raise_for_status()
104
+ return response.json()
105
+
106
+ def send_text_message_sync(
107
+ self,
108
+ text: str = "",
109
+ recipient: Optional[str] = None,
110
+ preview_url: bool = False,
111
+ recipient_type: str = "individual",
112
+ ) -> str:
113
+ """Send a text message to a WhatsApp user (synchronous version).
114
+
115
+ Args:
116
+ text: The text message to send
117
+ recipient: Recipient's WhatsApp ID or phone number (e.g., "+1234567890"). If not provided, uses default_recipient
118
+ preview_url: Whether to generate previews for links in the message
119
+
120
+ Returns:
121
+ Success message with message ID
122
+ """
123
+ # Use default recipient if none provided
124
+ if recipient is None:
125
+ if not self.default_recipient:
126
+ raise ValueError("No recipient provided and no default recipient set")
127
+ recipient = self.default_recipient
128
+ logger.debug(f"Using default recipient: {recipient}")
129
+
130
+ logger.debug(f"Sending WhatsApp message to {recipient}: {text}")
131
+ logger.debug(f"Current config - Phone Number ID: {self.phone_number_id}, Version: {self.version}")
132
+
133
+ data = {
134
+ "messaging_product": "whatsapp",
135
+ "recipient_type": recipient_type,
136
+ "to": recipient,
137
+ "type": "text",
138
+ "text": {"preview_url": preview_url, "body": text},
139
+ }
140
+
141
+ try:
142
+ response = self._send_message_sync(data)
143
+ message_id = response.get("messages", [{}])[0].get("id", "unknown")
144
+ return f"Message sent successfully! Message ID: {message_id}"
145
+ except httpx.HTTPStatusError as e:
146
+ logger.error(f"Failed to send WhatsApp message: {e}")
147
+ logger.error(f"Error response: {e.response.text if hasattr(e, 'response') else 'No response text'}")
148
+ raise
149
+ except Exception as e:
150
+ logger.error(f"Unexpected error sending WhatsApp message: {str(e)}")
151
+ raise
152
+
153
+ def send_template_message_sync(
154
+ self,
155
+ recipient: Optional[str] = None,
156
+ template_name: str = "",
157
+ language_code: str = "en_US",
158
+ components: Optional[List[Dict[str, Any]]] = None,
159
+ ) -> str:
160
+ """Send a template message to a WhatsApp user (synchronous version).
161
+
162
+ Args:
163
+ recipient: Recipient's WhatsApp ID or phone number (e.g., "+1234567890"). If not provided, uses default_recipient
164
+ template_name: Name of the template to use
165
+ language_code: Language code for the template (e.g., "en_US")
166
+ components: Optional list of template components (header, body, buttons)
167
+
168
+ Returns:
169
+ Success message with message ID
170
+ """
171
+ # Use default recipient if none provided
172
+ if recipient is None:
173
+ if not self.default_recipient:
174
+ raise ValueError("No recipient provided and no default recipient set")
175
+ recipient = self.default_recipient
176
+
177
+ logger.debug(f"Sending WhatsApp template message to {recipient}: {template_name}")
178
+
179
+ data = {
180
+ "messaging_product": "whatsapp",
181
+ "to": recipient,
182
+ "type": "template",
183
+ "template": {"name": template_name, "language": {"code": language_code}},
184
+ }
185
+
186
+ if components:
187
+ data["template"]["components"] = components # type: ignore[index]
188
+
189
+ try:
190
+ response = self._send_message_sync(data)
191
+ message_id = response.get("messages", [{}])[0].get("id", "unknown")
192
+ return f"Template message sent successfully! Message ID: {message_id}"
193
+ except httpx.HTTPStatusError as e:
194
+ logger.error(f"Failed to send WhatsApp template message: {e}")
195
+ raise
196
+
197
+ async def send_text_message_async(
198
+ self,
199
+ text: str = "",
200
+ recipient: Optional[str] = None,
201
+ preview_url: bool = False,
202
+ recipient_type: str = "individual",
203
+ ) -> str:
204
+ """Send a text message to a WhatsApp user (asynchronous version).
205
+
206
+ Args:
207
+ text: The text message to send
208
+ recipient: Recipient's WhatsApp ID or phone number (e.g., "+1234567890"). If not provided, uses default_recipient
209
+ preview_url: Whether to generate previews for links in the message
210
+
211
+ Returns:
212
+ Success message with message ID
213
+ """
214
+ # Use default recipient if none provided
215
+ if recipient is None:
216
+ if not self.default_recipient:
217
+ raise ValueError("No recipient provided and no default recipient set")
218
+ recipient = self.default_recipient
219
+ logger.debug(f"Using default recipient: {recipient}")
220
+
221
+ logger.debug(f"Sending WhatsApp message to {recipient}: {text}")
222
+ logger.debug(f"Current config - Phone Number ID: {self.phone_number_id}, Version: {self.version}")
223
+
224
+ data = {
225
+ "messaging_product": "whatsapp",
226
+ "recipient_type": recipient_type,
227
+ "to": recipient,
228
+ "type": "text",
229
+ "text": {"preview_url": preview_url, "body": text},
230
+ }
231
+
232
+ try:
233
+ response = await self._send_message_async(data)
234
+ message_id = response.get("messages", [{}])[0].get("id", "unknown")
235
+ return f"Message sent successfully! Message ID: {message_id}"
236
+ except httpx.HTTPStatusError as e:
237
+ logger.error(f"Failed to send WhatsApp message: {e}")
238
+ logger.error(f"Error response: {e.response.text if hasattr(e, 'response') else 'No response text'}")
239
+ raise
240
+ except Exception as e:
241
+ logger.error(f"Unexpected error sending WhatsApp message: {str(e)}")
242
+ raise
243
+
244
+ async def send_template_message_async(
245
+ self,
246
+ recipient: Optional[str] = None,
247
+ template_name: str = "",
248
+ language_code: str = "en_US",
249
+ components: Optional[List[Dict[str, Any]]] = None,
250
+ ) -> str:
251
+ """Send a template message to a WhatsApp user (asynchronous version).
252
+
253
+ Args:
254
+ recipient: Recipient's WhatsApp ID or phone number (e.g., "+1234567890"). If not provided, uses default_recipient
255
+ template_name: Name of the template to use
256
+ language_code: Language code for the template (e.g., "en_US")
257
+ components: Optional list of template components (header, body, buttons)
258
+
259
+ Returns:
260
+ Success message with message ID
261
+ """
262
+ # Use default recipient if none provided
263
+ if recipient is None:
264
+ if not self.default_recipient:
265
+ raise ValueError("No recipient provided and no default recipient set")
266
+ recipient = self.default_recipient
267
+
268
+ logger.debug(f"Sending WhatsApp template message to {recipient}: {template_name}")
269
+
270
+ data = {
271
+ "messaging_product": "whatsapp",
272
+ "to": recipient,
273
+ "type": "template",
274
+ "template": {"name": template_name, "language": {"code": language_code}},
275
+ }
276
+
277
+ if components:
278
+ data["template"]["components"] = components # type: ignore[index]
279
+
280
+ try:
281
+ response = await self._send_message_async(data)
282
+ message_id = response.get("messages", [{}])[0].get("id", "unknown")
283
+ return f"Template message sent successfully! Message ID: {message_id}"
284
+ except httpx.HTTPStatusError as e:
285
+ logger.error(f"Failed to send WhatsApp template message: {e}")
286
+ raise
agno/tools/wikipedia.py CHANGED
@@ -1,21 +1,29 @@
1
1
  import json
2
2
  from typing import List, Optional
3
3
 
4
- from agno.document import Document
5
- from agno.knowledge.wikipedia import WikipediaKnowledgeBase
4
+ from agno.knowledge.document import Document
5
+ from agno.knowledge.knowledge import Knowledge
6
+ from agno.knowledge.reader.wikipedia_reader import WikipediaReader
6
7
  from agno.tools import Toolkit
7
- from agno.utils.log import logger
8
+ from agno.utils.log import log_debug, log_info
8
9
 
9
10
 
10
11
  class WikipediaTools(Toolkit):
11
- def __init__(self, knowledge_base: Optional[WikipediaKnowledgeBase] = None):
12
- super().__init__(name="wikipedia_tools")
13
- self.knowledge_base: Optional[WikipediaKnowledgeBase] = knowledge_base
14
-
15
- if self.knowledge_base is not None and isinstance(self.knowledge_base, WikipediaKnowledgeBase):
16
- self.register(self.search_wikipedia_and_update_knowledge_base)
12
+ def __init__(
13
+ self,
14
+ knowledge: Optional[Knowledge] = None,
15
+ all: bool = False,
16
+ **kwargs,
17
+ ):
18
+ tools = []
19
+
20
+ self.knowledge: Optional[Knowledge] = knowledge
21
+ if self.knowledge is not None and isinstance(self.knowledge, Knowledge):
22
+ tools.append(self.search_wikipedia_and_update_knowledge_base)
17
23
  else:
18
- self.register(self.search_wikipedia)
24
+ tools.append(self.search_wikipedia) # type: ignore
25
+
26
+ super().__init__(name="wikipedia_tools", tools=tools, **kwargs)
19
27
 
20
28
  def search_wikipedia_and_update_knowledge_base(self, topic: str) -> str:
21
29
  """This function searches wikipedia for a topic, adds the results to the knowledge base and returns them.
@@ -26,15 +34,16 @@ class WikipediaTools(Toolkit):
26
34
  :return: Relevant documents from Wikipedia knowledge base.
27
35
  """
28
36
 
29
- if self.knowledge_base is None:
30
- return "Knowledge base not provided"
37
+ if self.knowledge is None:
38
+ return "Knowledge not provided"
31
39
 
32
- logger.debug(f"Adding to knowledge base: {topic}")
33
- self.knowledge_base.topics.append(topic)
34
- logger.debug("Loading knowledge base.")
35
- self.knowledge_base.load(recreate=False)
36
- logger.debug(f"Searching knowledge base: {topic}")
37
- relevant_docs: List[Document] = self.knowledge_base.search(query=topic)
40
+ log_debug(f"Adding to knowledge: {topic}")
41
+ self.knowledge.add_content(
42
+ topics=[topic],
43
+ reader=WikipediaReader(),
44
+ )
45
+ log_debug(f"Searching knowledge: {topic}")
46
+ relevant_docs: List[Document] = self.knowledge.search(query=topic)
38
47
  return json.dumps([doc.to_dict() for doc in relevant_docs])
39
48
 
40
49
  def search_wikipedia(self, query: str) -> str:
@@ -50,5 +59,5 @@ class WikipediaTools(Toolkit):
50
59
  "The `wikipedia` package is not installed. Please install it via `pip install wikipedia`."
51
60
  )
52
61
 
53
- logger.info(f"Searching wikipedia for: {query}")
62
+ log_info(f"Searching wikipedia for: {query}")
54
63
  return json.dumps(Document(name=query, content=wikipedia.summary(query)).to_dict())
agno/tools/workflow.py ADDED
@@ -0,0 +1,285 @@
1
+ import json
2
+ from textwrap import dedent
3
+ from typing import Any, Dict, Optional
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+ from agno.tools import Toolkit
8
+ from agno.utils.log import log_debug, log_error
9
+ from agno.workflow.workflow import Workflow, WorkflowRunOutput
10
+
11
+
12
+ class RunWorkflowInput(BaseModel):
13
+ input_data: str = Field(..., description="The input data for the workflow.")
14
+ additional_data: Optional[Dict[str, Any]] = Field(default=None, description="The additional data for the workflow.")
15
+
16
+
17
+ class WorkflowTools(Toolkit):
18
+ def __init__(
19
+ self,
20
+ workflow: Workflow,
21
+ enable_run_workflow: bool = True,
22
+ enable_think: bool = False,
23
+ enable_analyze: bool = False,
24
+ all: bool = False,
25
+ instructions: Optional[str] = None,
26
+ add_instructions: bool = True,
27
+ add_few_shot: bool = False,
28
+ few_shot_examples: Optional[str] = None,
29
+ async_mode: bool = False,
30
+ **kwargs,
31
+ ):
32
+ # Add instructions for using this toolkit
33
+ if instructions is None:
34
+ self.instructions = self.DEFAULT_INSTRUCTIONS
35
+ if add_few_shot:
36
+ if few_shot_examples is not None:
37
+ self.instructions += "\n" + few_shot_examples
38
+ else:
39
+ self.instructions = instructions
40
+
41
+ # The workflow to execute
42
+ self.workflow: Workflow = workflow
43
+
44
+ super().__init__(
45
+ name="workflow_tools",
46
+ instructions=self.instructions,
47
+ add_instructions=add_instructions,
48
+ auto_register=False,
49
+ **kwargs,
50
+ )
51
+
52
+ if enable_think or all:
53
+ if async_mode:
54
+ self.register(self.async_think, name="think")
55
+ else:
56
+ self.register(self.think, name="think")
57
+ if enable_run_workflow or all:
58
+ if async_mode:
59
+ self.register(self.async_run_workflow, name="run_workflow")
60
+ else:
61
+ self.register(self.run_workflow, name="run_workflow")
62
+ if enable_analyze or all:
63
+ if async_mode:
64
+ self.register(self.async_analyze, name="analyze")
65
+ else:
66
+ self.register(self.analyze, name="analyze")
67
+
68
+ def think(self, session_state: Dict[str, Any], thought: str) -> str:
69
+ """Use this tool as a scratchpad to reason about the workflow execution, refine your approach, brainstorm workflow inputs, or revise your plan.
70
+ Call `Think` whenever you need to figure out what to do next, analyze the user's requirements, plan workflow inputs, or decide on execution strategy.
71
+ You should use this tool as frequently as needed.
72
+ Args:
73
+ thought: Your thought process and reasoning about workflow execution.
74
+ """
75
+ try:
76
+ log_debug(f"Workflow Thought: {thought}")
77
+
78
+ # Add the thought to the session state
79
+ if session_state is None:
80
+ session_state = {}
81
+ if "workflow_thoughts" not in session_state:
82
+ session_state["workflow_thoughts"] = []
83
+ session_state["workflow_thoughts"].append(thought)
84
+
85
+ # Return the full log of thoughts and the new thought
86
+ thoughts = "\n".join([f"- {t}" for t in session_state["workflow_thoughts"]])
87
+ formatted_thoughts = dedent(
88
+ f"""Workflow Thoughts:
89
+ {thoughts}
90
+ """
91
+ ).strip()
92
+ return formatted_thoughts
93
+ except Exception as e:
94
+ log_error(f"Error recording workflow thought: {e}")
95
+ return f"Error recording workflow thought: {e}"
96
+
97
+ async def async_think(self, session_state: Dict[str, Any], thought: str) -> str:
98
+ """Use this tool as a scratchpad to reason about the workflow execution, refine your approach, brainstorm workflow inputs, or revise your plan.
99
+ Call `Think` whenever you need to figure out what to do next, analyze the user's requirements, plan workflow inputs, or decide on execution strategy.
100
+ You should use this tool as frequently as needed.
101
+ Args:
102
+ thought: Your thought process and reasoning about workflow execution.
103
+ """
104
+ try:
105
+ log_debug(f"Workflow Thought: {thought}")
106
+
107
+ # Add the thought to the session state
108
+ if session_state is None:
109
+ session_state = {}
110
+ if "workflow_thoughts" not in session_state:
111
+ session_state["workflow_thoughts"] = []
112
+ session_state["workflow_thoughts"].append(thought)
113
+
114
+ # Return the full log of thoughts and the new thought
115
+ thoughts = "\n".join([f"- {t}" for t in session_state["workflow_thoughts"]])
116
+ formatted_thoughts = dedent(
117
+ f"""Workflow Thoughts:
118
+ {thoughts}
119
+ """
120
+ ).strip()
121
+ return formatted_thoughts
122
+ except Exception as e:
123
+ log_error(f"Error recording workflow thought: {e}")
124
+ return f"Error recording workflow thought: {e}"
125
+
126
+ def run_workflow(
127
+ self,
128
+ session_state: Dict[str, Any],
129
+ input: RunWorkflowInput,
130
+ ) -> str:
131
+ """Use this tool to execute the workflow with the specified inputs and parameters.
132
+ After thinking through the requirements, use this tool to run the workflow with appropriate inputs.
133
+
134
+ Args:
135
+ input: The input data for the workflow.
136
+ """
137
+ if isinstance(input, dict):
138
+ input = RunWorkflowInput.model_validate(input)
139
+
140
+ try:
141
+ log_debug(f"Running workflow with input: {input.input_data}")
142
+
143
+ user_id = session_state.get("current_user_id")
144
+ session_id = session_state.get("current_session_id")
145
+
146
+ # Execute the workflow
147
+ result: WorkflowRunOutput = self.workflow.run(
148
+ input=input.input_data,
149
+ user_id=user_id,
150
+ session_id=session_id,
151
+ session_state=session_state,
152
+ additional_data=input.additional_data,
153
+ )
154
+
155
+ if "workflow_results" not in session_state:
156
+ session_state["workflow_results"] = []
157
+
158
+ session_state["workflow_results"].append(result.to_dict())
159
+
160
+ return json.dumps(result.to_dict(), indent=2)
161
+
162
+ except Exception as e:
163
+ log_error(f"Error running workflow: {e}")
164
+ return f"Error running workflow: {e}"
165
+
166
+ async def async_run_workflow(
167
+ self,
168
+ session_state: Dict[str, Any],
169
+ input: RunWorkflowInput,
170
+ ) -> str:
171
+ """Use this tool to execute the workflow with the specified inputs and parameters.
172
+ After thinking through the requirements, use this tool to run the workflow with appropriate inputs.
173
+ Args:
174
+ input_data: The input data for the workflow (use a `str` for a simple input)
175
+ additional_data: The additional data for the workflow. This is a dictionary of key-value pairs that will be passed to the workflow. E.g. {"topic": "food", "style": "Humour"}
176
+ """
177
+ if isinstance(input, dict):
178
+ input = RunWorkflowInput.model_validate(input)
179
+
180
+ try:
181
+ log_debug(f"Running workflow with input: {input.input_data}")
182
+
183
+ user_id = session_state.get("current_user_id")
184
+ session_id = session_state.get("current_session_id")
185
+
186
+ # Execute the workflow
187
+ result: WorkflowRunOutput = await self.workflow.arun(
188
+ input=input.input_data,
189
+ user_id=user_id,
190
+ session_id=session_id,
191
+ session_state=session_state,
192
+ additional_data=input.additional_data,
193
+ )
194
+
195
+ if "workflow_results" not in session_state:
196
+ session_state["workflow_results"] = []
197
+
198
+ session_state["workflow_results"].append(result.to_dict())
199
+
200
+ return json.dumps(result.to_dict(), indent=2)
201
+
202
+ except Exception as e:
203
+ log_error(f"Error running workflow: {e}")
204
+ return f"Error running workflow: {e}"
205
+
206
+ def analyze(self, session_state: Dict[str, Any], analysis: str) -> str:
207
+ """Use this tool to evaluate whether the workflow execution results are correct and sufficient.
208
+ If not, go back to "Think" or "Run" with refined inputs or parameters.
209
+ Args:
210
+ analysis: Your analysis of the workflow execution results.
211
+ """
212
+ try:
213
+ log_debug(f"Workflow Analysis: {analysis}")
214
+
215
+ # Add the analysis to the session state
216
+ if session_state is None:
217
+ session_state = {}
218
+ if "workflow_analysis" not in session_state:
219
+ session_state["workflow_analysis"] = []
220
+ session_state["workflow_analysis"].append(analysis)
221
+
222
+ # Return the full log of analysis and the new analysis
223
+ analysis_log = "\n".join([f"- {a}" for a in session_state["workflow_analysis"]])
224
+ formatted_analysis = dedent(
225
+ f"""Workflow Analysis:
226
+ {analysis_log}
227
+ """
228
+ ).strip()
229
+ return formatted_analysis
230
+ except Exception as e:
231
+ log_error(f"Error recording workflow analysis: {e}")
232
+ return f"Error recording workflow analysis: {e}"
233
+
234
+ async def async_analyze(self, session_state: Dict[str, Any], analysis: str) -> str:
235
+ """Use this tool to evaluate whether the workflow execution results are correct and sufficient.
236
+ If not, go back to "Think" or "Run" with refined inputs or parameters.
237
+ Args:
238
+ analysis: Your analysis of the workflow execution results.
239
+ """
240
+ try:
241
+ log_debug(f"Workflow Analysis: {analysis}")
242
+
243
+ # Add the analysis to the session state
244
+ if session_state is None:
245
+ session_state = {}
246
+ if "workflow_analysis" not in session_state:
247
+ session_state["workflow_analysis"] = []
248
+ session_state["workflow_analysis"].append(analysis)
249
+
250
+ # Return the full log of analysis and the new analysis
251
+ analysis_log = "\n".join([f"- {a}" for a in session_state["workflow_analysis"]])
252
+ formatted_analysis = dedent(
253
+ f"""Workflow Analysis:
254
+ {analysis_log}
255
+ """
256
+ ).strip()
257
+ return formatted_analysis
258
+ except Exception as e:
259
+ log_error(f"Error recording workflow analysis: {e}")
260
+ return f"Error recording workflow analysis: {e}"
261
+
262
+ DEFAULT_INSTRUCTIONS = dedent("""\
263
+ You have access to the Think, Run Workflow, and Analyze tools that will help you execute workflows and analyze their results. Use these tools as frequently as needed to successfully complete workflow-based tasks.
264
+ ## How to use the Think, Run Workflow, and Analyze tools:
265
+
266
+ 1. **Think**
267
+ - Purpose: A scratchpad for planning workflow execution, brainstorming inputs, and refining your approach. You never reveal your "Think" content to the user.
268
+ - Usage: Call `think` whenever you need to figure out what workflow inputs to use, analyze requirements, or decide on execution strategy before (or after) you run the workflow.
269
+ 2. **Run Workflow**
270
+ - Purpose: Executes the workflow with specified inputs and parameters.
271
+ - Usage: Call `run_workflow` with appropriate input data whenever you want to execute the workflow.
272
+ - For all workflows, start with simple inputs and gradually increase complexity
273
+ 3. **Analyze**
274
+ - Purpose: Evaluate whether the workflow execution results are correct and sufficient. If not, go back to "Think" or "Run Workflow" with refined inputs.
275
+ - Usage: Call `analyze` after getting workflow results to verify the quality and correctness of the execution. Consider:
276
+ - Completeness: Did the workflow complete all expected steps?
277
+ - Quality: Are the results accurate and meet the requirements?
278
+ - Errors: Were there any failures or unexpected behaviors?
279
+ **Important Guidelines**:
280
+ - Do not include your internal chain-of-thought in direct user responses.
281
+ - Use "Think" to reason internally. These notes are never exposed to the user.
282
+ - When you provide a final answer to the user, be clear, concise, and based on the workflow results.
283
+ - If workflow execution fails or produces unexpected results, acknowledge limitations and explain what went wrong.
284
+ - Synthesize information from multiple workflow runs if you execute the workflow several times with different inputs.\
285
+ """)