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
@@ -0,0 +1,377 @@
1
+ """
2
+ Google Sheets Toolset for interacting with Sheets API
3
+
4
+ Required Environment Variables:
5
+ -----------------------------
6
+ - GOOGLE_CLIENT_ID: Google OAuth client ID
7
+ - GOOGLE_CLIENT_SECRET: Google OAuth client secret
8
+ - GOOGLE_PROJECT_ID: Google Cloud project ID
9
+ - GOOGLE_REDIRECT_URI: Google OAuth redirect URI (default: http://localhost)
10
+
11
+ How to Get These Credentials:
12
+ ---------------------------
13
+ 1. Go to Google Cloud Console (https://console.cloud.google.com)
14
+ 2. Create a new project or select an existing one
15
+ 3. Enable the Google Sheets API:
16
+ - Go to "APIs & Services" > "Enable APIs and Services"
17
+ - Search for "Google Sheets API"
18
+ - Click "Enable"
19
+
20
+ 4. Create OAuth 2.0 credentials:
21
+ - Go to "APIs & Services" > "Credentials"
22
+ - Click "Create Credentials" > "OAuth client ID"
23
+ - Go through the OAuth consent screen setup
24
+ - Give it a name and click "Create"
25
+ - You'll receive:
26
+ * Client ID (GOOGLE_CLIENT_ID)
27
+ * Client Secret (GOOGLE_CLIENT_SECRET)
28
+ - The Project ID (GOOGLE_PROJECT_ID) is visible in the project dropdown at the top of the page
29
+
30
+ 5. Set up environment variables:
31
+ Create a .envrc file in your project root with:
32
+ ```
33
+ export GOOGLE_CLIENT_ID=your_client_id_here
34
+ export GOOGLE_CLIENT_SECRET=your_client_secret_here
35
+ export GOOGLE_PROJECT_ID=your_project_id_here
36
+ export GOOGLE_REDIRECT_URI=http://localhost # Default value
37
+ ```
38
+
39
+ Alternatively, follow the instructions in the Google Sheets API Quickstart guide:
40
+ 1: Steps: https://developers.google.com/sheets/api/quickstart/python
41
+ 2: Save the credentials.json file to the root of the project or update the path in the GoogleSheetsTools class
42
+
43
+ Note: The first time you run the application, it will open a browser window for OAuth authentication.
44
+ A token.json file will be created to store the authentication credentials for future use.
45
+ """
46
+
47
+ import json
48
+ from functools import wraps
49
+ from os import getenv
50
+ from pathlib import Path
51
+ from typing import Any, List, Optional, Union
52
+
53
+ from agno.tools import Toolkit
54
+
55
+ try:
56
+ from google.auth.transport.requests import Request
57
+ from google.oauth2.credentials import Credentials
58
+ from google.oauth2.service_account import Credentials as ServiceAccountCredentials
59
+ from google_auth_oauthlib.flow import InstalledAppFlow
60
+ from googleapiclient.discovery import Resource, build
61
+ except ImportError:
62
+ raise ImportError(
63
+ "`google-api-python-client` `google-auth-httplib2` `google-auth-oauthlib` not installed. Please install using `pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib`"
64
+ )
65
+
66
+
67
+ def authenticate(func):
68
+ """Decorator to ensure authentication before executing a function."""
69
+
70
+ @wraps(func)
71
+ def wrapper(self, *args, **kwargs):
72
+ if not self.creds or not self.creds.valid:
73
+ self._auth()
74
+ if not self.service:
75
+ self.service = build("sheets", "v4", credentials=self.creds)
76
+ return func(self, *args, **kwargs)
77
+
78
+ return wrapper
79
+
80
+
81
+ class GoogleSheetsTools(Toolkit):
82
+ # Default scopes for Google Sheets API access
83
+ DEFAULT_SCOPES = {
84
+ "read": "https://www.googleapis.com/auth/spreadsheets.readonly",
85
+ "write": "https://www.googleapis.com/auth/spreadsheets",
86
+ }
87
+
88
+ service: Optional[Resource]
89
+
90
+ def __init__(
91
+ self,
92
+ scopes: Optional[List[str]] = None,
93
+ spreadsheet_id: Optional[str] = None,
94
+ spreadsheet_range: Optional[str] = None,
95
+ creds: Optional[Union[Credentials, ServiceAccountCredentials]] = None,
96
+ creds_path: Optional[str] = None,
97
+ token_path: Optional[str] = None,
98
+ service_account_path: Optional[str] = None,
99
+ oauth_port: int = 0,
100
+ enable_read_sheet: bool = True,
101
+ enable_create_sheet: bool = False,
102
+ enable_update_sheet: bool = False,
103
+ enable_create_duplicate_sheet: bool = False,
104
+ all: bool = False,
105
+ **kwargs,
106
+ ):
107
+ """Initialize GoogleSheetsTools with the specified configuration.
108
+
109
+ Args:
110
+ scopes (Optional[List[str]]): Custom OAuth scopes. If None, uses write scope by default.
111
+ spreadsheet_id (Optional[str]): ID of the target spreadsheet.
112
+ spreadsheet_range (Optional[str]): Range within the spreadsheet.
113
+ creds (Optional[Credentials | ServiceAccountCredentials]): Pre-existing credentials.
114
+ creds_path (Optional[str]): Path to credentials file.
115
+ token_path (Optional[str]): Path to token file.
116
+ service_account_path (Optional[str]): Path to a service account file.
117
+ oauth_port (int): Port to use for OAuth authentication. Defaults to 0.
118
+ enable_read_sheet (bool): Enable reading from a sheet.
119
+ enable_create_sheet (bool): Enable creating a sheet.
120
+ enable_update_sheet (bool): Enable updating a sheet.
121
+ enable_create_duplicate_sheet (bool): Enable creating a duplicate sheet.
122
+ all (bool): Enable all tools.
123
+ """
124
+
125
+ self.spreadsheet_id = spreadsheet_id
126
+ self.spreadsheet_range = spreadsheet_range
127
+ self.creds = creds
128
+ self.credentials_path = creds_path
129
+ self.token_path = token_path
130
+ self.oauth_port = oauth_port
131
+ self.service: Optional[Resource] = None
132
+ self.service_account_path = service_account_path
133
+
134
+ # Determine required scopes based on operations if no custom scopes provided
135
+ if scopes is None:
136
+ self.scopes = []
137
+ if enable_read_sheet:
138
+ self.scopes.append(self.DEFAULT_SCOPES["read"])
139
+ if enable_create_sheet or enable_update_sheet or enable_create_duplicate_sheet:
140
+ self.scopes.append(self.DEFAULT_SCOPES["write"])
141
+ # Remove duplicates while preserving order
142
+ self.scopes = list(dict.fromkeys(self.scopes))
143
+ else:
144
+ self.scopes = scopes
145
+ # Validate that required scopes are present for requested operations
146
+ if (enable_create_sheet or enable_update_sheet or enable_create_duplicate_sheet) and self.DEFAULT_SCOPES[
147
+ "write"
148
+ ] not in self.scopes:
149
+ raise ValueError(f"The scope {self.DEFAULT_SCOPES['write']} is required for write operations")
150
+ if (
151
+ enable_read_sheet
152
+ and self.DEFAULT_SCOPES["read"] not in self.scopes
153
+ and self.DEFAULT_SCOPES["write"] not in self.scopes
154
+ ):
155
+ raise ValueError(
156
+ f"Either {self.DEFAULT_SCOPES['read']} or {self.DEFAULT_SCOPES['write']} is required for read operations"
157
+ )
158
+
159
+ tools: List[Any] = []
160
+ if all or enable_read_sheet:
161
+ tools.append(self.read_sheet)
162
+ if all or enable_create_sheet:
163
+ tools.append(self.create_sheet)
164
+ if all or enable_update_sheet:
165
+ tools.append(self.update_sheet)
166
+ if all or enable_create_duplicate_sheet:
167
+ tools.append(self.create_duplicate_sheet)
168
+
169
+ super().__init__(name="google_sheets_tools", tools=tools, **kwargs)
170
+
171
+ def _auth(self) -> None:
172
+ """
173
+ Authenticate with Google Sheets API
174
+ """
175
+ if self.creds and self.creds.valid:
176
+ return
177
+
178
+ service_account_path = self.service_account_path or getenv("GOOGLE_SERVICE_ACCOUNT_FILE")
179
+
180
+ if service_account_path:
181
+ self.creds = ServiceAccountCredentials.from_service_account_file(
182
+ service_account_path,
183
+ scopes=self.scopes,
184
+ )
185
+ if self.creds and self.creds.expired:
186
+ self.creds.refresh(Request())
187
+ return
188
+
189
+ token_file = Path(self.token_path or "token.json")
190
+ creds_file = Path(self.credentials_path or "credentials.json")
191
+
192
+ if token_file.exists():
193
+ self.creds = Credentials.from_authorized_user_file(str(token_file), self.scopes)
194
+
195
+ if not self.creds or not self.creds.valid:
196
+ if self.creds and self.creds.expired and self.creds.refresh_token: # type: ignore
197
+ self.creds.refresh(Request())
198
+ else:
199
+ client_config = {
200
+ "installed": {
201
+ "client_id": getenv("GOOGLE_CLIENT_ID"),
202
+ "client_secret": getenv("GOOGLE_CLIENT_SECRET"),
203
+ "project_id": getenv("GOOGLE_PROJECT_ID"),
204
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
205
+ "token_uri": "https://oauth2.googleapis.com/token",
206
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
207
+ "redirect_uris": [getenv("GOOGLE_REDIRECT_URI", "http://localhost")],
208
+ }
209
+ }
210
+ # File based authentication
211
+ if creds_file.exists():
212
+ flow = InstalledAppFlow.from_client_secrets_file(str(creds_file), self.scopes)
213
+ else:
214
+ flow = InstalledAppFlow.from_client_config(client_config, self.scopes)
215
+ # Opens up a browser window for OAuth authentication
216
+ self.creds = flow.run_local_server(port=self.oauth_port)
217
+ token_file.write_text(self.creds.to_json()) if self.creds else None # type: ignore
218
+
219
+ @authenticate
220
+ def read_sheet(self, spreadsheet_id: Optional[str] = None, spreadsheet_range: Optional[str] = None) -> str:
221
+ """
222
+ Read values from a Google Sheet. Prioritizes instance attributes over method parameters.
223
+
224
+ Args:
225
+ spreadsheet_id: Fallback spreadsheet ID if instance attribute is None
226
+ spreadsheet_range: Fallback range if instance attribute is None
227
+
228
+ Returns:
229
+ JSON of list of rows, where each row is a list of values
230
+ """
231
+ if not self.creds:
232
+ return "Not authenticated. Call auth() first."
233
+
234
+ # Prioritize instance attributes
235
+ sheet_id = self.spreadsheet_id or spreadsheet_id
236
+ sheet_range = self.spreadsheet_range or spreadsheet_range
237
+
238
+ if not sheet_id or not sheet_range:
239
+ return "Spreadsheet ID and range must be provided either in constructor or method call"
240
+
241
+ try:
242
+ result = self.service.spreadsheets().values().get(spreadsheetId=sheet_id, range=sheet_range).execute() # type: ignore
243
+ return json.dumps(result.get("values", []))
244
+
245
+ except Exception as e:
246
+ return f"Error reading Google Sheet: {e}"
247
+
248
+ @authenticate
249
+ def create_sheet(self, title: str) -> str:
250
+ """
251
+ Create a Google Sheet with a given title.
252
+
253
+ Args:
254
+ title: The title of the Google Sheet
255
+
256
+ Returns:
257
+ The ID of the created Google Sheet
258
+ """
259
+ if not self.creds:
260
+ return "Not authenticated. Call auth() first."
261
+
262
+ try:
263
+ spreadsheet = {"properties": {"title": title}}
264
+
265
+ spreadsheet = self.service.spreadsheets().create(body=spreadsheet, fields="spreadsheetId").execute() # type: ignore
266
+ spreadsheet_id = spreadsheet.get("spreadsheetId")
267
+
268
+ return f"Spreadsheet created: https://docs.google.com/spreadsheets/d/{spreadsheet_id}"
269
+
270
+ except Exception as e:
271
+ return f"Error creating Google Sheet: {e}"
272
+
273
+ @authenticate
274
+ def update_sheet(
275
+ self, data: List[List[Any]], spreadsheet_id: Optional[str] = None, range_name: Optional[str] = None
276
+ ) -> str:
277
+ """Updates a Google Sheet with the provided data.
278
+
279
+ Note: This function can overwrite existing data in the sheet.
280
+ User needs to ensure that the provided range correctly matches the data that needs to be updated.
281
+
282
+ Args:
283
+ data: The data to update the sheet with
284
+ spreadsheet_id: The ID of the Google Sheet
285
+ range_name: The range of the Google Sheet to update
286
+
287
+ Returns:
288
+ A message indicating the success or failure of the operation
289
+ """
290
+ if not self.creds:
291
+ return "Not authenticated. Call auth() first."
292
+
293
+ try:
294
+ # Define the request body
295
+ body = {"values": data}
296
+
297
+ # Update the sheet
298
+ self.service.spreadsheets().values().update( # type: ignore
299
+ spreadsheetId=spreadsheet_id,
300
+ range=range_name,
301
+ valueInputOption="RAW",
302
+ body=body,
303
+ ).execute()
304
+
305
+ return f"Sheet updated successfully: {spreadsheet_id}"
306
+
307
+ except Exception as e:
308
+ return f"Error updating Google Sheet: {e}"
309
+
310
+ @authenticate
311
+ def create_duplicate_sheet(
312
+ self, source_id: str, new_title: Optional[str] = None, copy_permissions: bool = True
313
+ ) -> str:
314
+ """Duplicate a Google Spreadsheet using the Google Drive API's copy feature.
315
+ This ensures an exact duplicate including formatting and data.
316
+
317
+ Note: Make sure your credentials include the drive scope 'https://www.googleapis.com/auth/drive'
318
+
319
+ Args:
320
+ source_id: The ID of the source spreadsheet.
321
+ new_title: Optional new title for the duplicated spreadsheet. If not provided, the source title will be used.
322
+ copy_permissions: Whether to copy the permissions from the source spreadsheet. Defaults to True.
323
+
324
+ Returns:
325
+ A link to the duplicated spreadsheet.
326
+ """
327
+ if not self.creds:
328
+ return "Not authenticated. Call auth() first."
329
+
330
+ if not self.service:
331
+ return "Service not initialized"
332
+
333
+ try:
334
+ # Ensure the drive scope is included
335
+ if "https://www.googleapis.com/auth/drive" not in self.scopes:
336
+ self.scopes.append("https://www.googleapis.com/auth/drive")
337
+ self._auth() # Re-authenticate with updated scopes
338
+
339
+ drive_service = build("drive", "v3", credentials=self.creds)
340
+
341
+ # Use new_title if provided, otherwise fetch the title from the source spreadsheet
342
+ if not new_title:
343
+ source_sheet = self.service.spreadsheets().get(spreadsheetId=source_id).execute()
344
+ new_title = source_sheet["properties"]["title"]
345
+
346
+ body = {"name": new_title}
347
+ new_file = drive_service.files().copy(fileId=source_id, body=body).execute()
348
+ new_spreadsheet_id = new_file.get("id")
349
+
350
+ # Copy permissions if requested
351
+ if copy_permissions:
352
+ # Get permissions from source file
353
+ source_permissions = (
354
+ drive_service.permissions()
355
+ .list(fileId=source_id, fields="permissions(emailAddress,role,type)")
356
+ .execute()
357
+ .get("permissions", [])
358
+ )
359
+
360
+ # Apply each permission to the new file
361
+ for permission in source_permissions:
362
+ # Skip the owner permission as it can't be transferred
363
+ if permission.get("role") == "owner":
364
+ continue
365
+
366
+ drive_service.permissions().create(
367
+ fileId=new_spreadsheet_id,
368
+ body={
369
+ "role": permission.get("role"),
370
+ "type": permission.get("type"),
371
+ "emailAddress": permission.get("emailAddress"),
372
+ },
373
+ ).execute()
374
+
375
+ return f"Spreadsheet duplicated successfully: https://docs.google.com/spreadsheets/d/{new_spreadsheet_id}"
376
+ except Exception as e:
377
+ return f"Error duplicating spreadsheet via Drive API: {e}"
agno/tools/hackernews.py CHANGED
@@ -1,24 +1,32 @@
1
1
  import json
2
+ from typing import Any, List
2
3
 
3
4
  import httpx
4
5
 
5
6
  from agno.tools import Toolkit
6
- from agno.utils.log import logger
7
+ from agno.utils.log import log_debug, logger
7
8
 
8
9
 
9
10
  class HackerNewsTools(Toolkit):
11
+ """
12
+ HackerNews is a tool for getting top stories from Hacker News.
13
+
14
+ Args:
15
+ enable_get_top_stories (bool): Enable getting top stories from Hacker News. Default is True.
16
+ enable_get_user_details (bool): Enable getting user details from Hacker News. Default is True.
17
+ all (bool): Enable all tools. Overrides individual flags when True. Default is False.
18
+ """
19
+
10
20
  def __init__(
11
- self,
12
- get_top_stories: bool = True,
13
- get_user_details: bool = True,
21
+ self, enable_get_top_stories: bool = True, enable_get_user_details: bool = True, all: bool = False, **kwargs
14
22
  ):
15
- super().__init__(name="hackers_news")
23
+ tools: List[Any] = []
24
+ if all or enable_get_top_stories:
25
+ tools.append(self.get_top_hackernews_stories)
26
+ if all or enable_get_user_details:
27
+ tools.append(self.get_user_details)
16
28
 
17
- # Register functions in the toolkit
18
- if get_top_stories:
19
- self.register(self.get_top_hackernews_stories)
20
- if get_user_details:
21
- self.register(self.get_user_details)
29
+ super().__init__(name="hackers_news", tools=tools, **kwargs)
22
30
 
23
31
  def get_top_hackernews_stories(self, num_stories: int = 10) -> str:
24
32
  """Use this function to get top stories from Hacker News.
@@ -30,7 +38,7 @@ class HackerNewsTools(Toolkit):
30
38
  str: JSON string of top stories.
31
39
  """
32
40
 
33
- logger.info(f"Getting top {num_stories} stories from Hacker News")
41
+ log_debug(f"Getting top {num_stories} stories from Hacker News")
34
42
  # Fetch top story IDs
35
43
  response = httpx.get("https://hacker-news.firebaseio.com/v0/topstories.json")
36
44
  story_ids = response.json()
@@ -55,7 +63,7 @@ class HackerNewsTools(Toolkit):
55
63
  """
56
64
 
57
65
  try:
58
- logger.info(f"Getting details for user: {username}")
66
+ log_debug(f"Getting details for user: {username}")
59
67
  user = httpx.get(f"https://hacker-news.firebaseio.com/v0/user/{username}.json").json()
60
68
  user_details = {
61
69
  "id": user.get("user_id"),
agno/tools/jina.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from os import getenv
2
- from typing import Dict, Optional
2
+ from typing import Any, Dict, List, Optional
3
3
 
4
4
  import httpx
5
5
  from pydantic import BaseModel, Field, HttpUrl
@@ -14,6 +14,7 @@ class JinaReaderToolsConfig(BaseModel):
14
14
  search_url: HttpUrl = Field("https://s.jina.ai/", description="Search URL for Jina Reader API") # type: ignore
15
15
  max_content_length: int = Field(10000, description="Maximum content length in characters")
16
16
  timeout: Optional[int] = Field(None, description="Timeout for Jina Reader API requests")
17
+ search_query_content: Optional[bool] = Field(False, description="Toggle full URL content in query search result")
17
18
 
18
19
 
19
20
  class JinaReaderTools(Toolkit):
@@ -24,28 +25,33 @@ class JinaReaderTools(Toolkit):
24
25
  search_url: str = "https://s.jina.ai/",
25
26
  max_content_length: int = 10000,
26
27
  timeout: Optional[int] = None,
27
- read_url: bool = True,
28
- search_query: bool = False,
28
+ search_query_content: bool = True,
29
+ enable_read_url: bool = True,
30
+ enable_search_query: bool = False,
31
+ all: bool = False,
32
+ **kwargs,
29
33
  ):
30
- super().__init__(name="jina_reader_tools")
31
-
34
+ self.api_key = api_key or getenv("JINA_API_KEY")
32
35
  self.config: JinaReaderToolsConfig = JinaReaderToolsConfig(
33
- api_key=api_key,
36
+ api_key=self.api_key,
34
37
  base_url=base_url,
35
38
  search_url=search_url,
36
39
  max_content_length=max_content_length,
37
40
  timeout=timeout,
41
+ search_query_content=search_query_content,
38
42
  )
39
43
 
40
- if read_url:
41
- self.register(self.read_url)
42
- if search_query:
43
- self.register(self.search_query)
44
+ tools: List[Any] = []
45
+ if all or enable_read_url:
46
+ tools.append(self.read_url)
47
+ if all or enable_search_query:
48
+ tools.append(self.search_query)
49
+
50
+ super().__init__(name="jina_reader_tools", tools=tools, **kwargs)
44
51
 
45
52
  def read_url(self, url: str) -> str:
46
53
  """Reads a URL and returns the truncated content using Jina Reader API."""
47
54
  full_url = f"{self.config.base_url}{url}"
48
- logger.info(f"Reading URL: {full_url}")
49
55
  try:
50
56
  response = httpx.get(full_url, headers=self._get_headers())
51
57
  response.raise_for_status()
@@ -58,10 +64,14 @@ class JinaReaderTools(Toolkit):
58
64
 
59
65
  def search_query(self, query: str) -> str:
60
66
  """Performs a web search using Jina Reader API and returns the truncated results."""
61
- full_url = f"{self.config.search_url}{query}"
62
- logger.info(f"Performing search: {full_url}")
67
+ full_url = f"{self.config.search_url}"
68
+ headers = self._get_headers()
69
+ if not self.config.search_query_content:
70
+ headers["X-Respond-With"] = "no-content" # to avoid returning full content in search results
71
+
72
+ body = {"q": query}
63
73
  try:
64
- response = httpx.get(full_url, headers=self._get_headers())
74
+ response = httpx.post(full_url, headers=headers, json=body)
65
75
  response.raise_for_status()
66
76
  content = response.json()
67
77
  return self._truncate_content(str(content))
agno/tools/jira.py CHANGED
@@ -1,9 +1,9 @@
1
1
  import json
2
- import os
3
- from typing import Optional, cast
2
+ from os import getenv
3
+ from typing import Any, List, Optional, cast
4
4
 
5
5
  from agno.tools import Toolkit
6
- from agno.utils.log import logger
6
+ from agno.utils.log import log_debug, logger
7
7
 
8
8
  try:
9
9
  from jira import JIRA, Issue
@@ -18,13 +18,18 @@ class JiraTools(Toolkit):
18
18
  username: Optional[str] = None,
19
19
  password: Optional[str] = None,
20
20
  token: Optional[str] = None,
21
+ enable_get_issue: bool = True,
22
+ enable_create_issue: bool = True,
23
+ enable_search_issues: bool = True,
24
+ enable_add_comment: bool = True,
25
+ enable_add_worklog: bool = True,
26
+ all: bool = False,
27
+ **kwargs,
21
28
  ):
22
- super().__init__(name="jira_tools")
23
-
24
- self.server_url = server_url or os.getenv("JIRA_SERVER_URL")
25
- self.username = username or os.getenv("JIRA_USERNAME")
26
- self.password = password or os.getenv("JIRA_PASSWORD")
27
- self.token = token or os.getenv("JIRA_TOKEN")
29
+ self.server_url = server_url or getenv("JIRA_SERVER_URL")
30
+ self.username = username or getenv("JIRA_USERNAME")
31
+ self.password = password or getenv("JIRA_PASSWORD")
32
+ self.token = token or getenv("JIRA_TOKEN")
28
33
 
29
34
  if not self.server_url:
30
35
  raise ValueError("JIRA server URL not provided.")
@@ -42,12 +47,19 @@ class JiraTools(Toolkit):
42
47
  else:
43
48
  self.jira = JIRA(server=self.server_url)
44
49
 
45
- # Register methods
46
- self.register(self.get_issue)
47
- self.register(self.create_issue)
48
- self.register(self.search_issues)
49
- self.register(self.add_comment)
50
- # You can register more methods here
50
+ tools: List[Any] = []
51
+ if enable_get_issue or all:
52
+ tools.append(self.get_issue)
53
+ if enable_create_issue or all:
54
+ tools.append(self.create_issue)
55
+ if enable_search_issues or all:
56
+ tools.append(self.search_issues)
57
+ if enable_add_comment or all:
58
+ tools.append(self.add_comment)
59
+ if enable_add_worklog or all:
60
+ tools.append(self.add_worklog)
61
+
62
+ super().__init__(name="jira_tools", tools=tools, **kwargs)
51
63
 
52
64
  def get_issue(self, issue_key: str) -> str:
53
65
  """
@@ -67,7 +79,7 @@ class JiraTools(Toolkit):
67
79
  "summary": issue.fields.summary,
68
80
  "description": issue.fields.description or "",
69
81
  }
70
- logger.debug(f"Issue details retrieved for {issue_key}: {issue_details}")
82
+ log_debug(f"Issue details retrieved for {issue_key}: {issue_details}")
71
83
  return json.dumps(issue_details)
72
84
  except Exception as e:
73
85
  logger.error(f"Error retrieving issue {issue_key}: {e}")
@@ -92,7 +104,7 @@ class JiraTools(Toolkit):
92
104
  }
93
105
  new_issue = self.jira.create_issue(fields=issue_dict)
94
106
  issue_url = f"{self.server_url}/browse/{new_issue.key}"
95
- logger.debug(f"Issue created with key: {new_issue.key}")
107
+ log_debug(f"Issue created with key: {new_issue.key}")
96
108
  return json.dumps({"key": new_issue.key, "url": issue_url})
97
109
  except Exception as e:
98
110
  logger.error(f"Error creating issue in project {project_key}: {e}")
@@ -118,7 +130,7 @@ class JiraTools(Toolkit):
118
130
  "assignee": issue.fields.assignee.displayName if issue.fields.assignee else "Unassigned",
119
131
  }
120
132
  results.append(issue_details)
121
- logger.debug(f"Found {len(results)} issues for JQL '{jql_str}'")
133
+ log_debug(f"Found {len(results)} issues for JQL '{jql_str}'")
122
134
  return json.dumps(results)
123
135
  except Exception as e:
124
136
  logger.error(f"Error searching issues with JQL '{jql_str}': {e}")
@@ -134,8 +146,25 @@ class JiraTools(Toolkit):
134
146
  """
135
147
  try:
136
148
  self.jira.add_comment(issue_key, comment)
137
- logger.debug(f"Comment added to issue {issue_key}")
149
+ log_debug(f"Comment added to issue {issue_key}")
138
150
  return json.dumps({"status": "success", "issue_key": issue_key})
139
151
  except Exception as e:
140
152
  logger.error(f"Error adding comment to issue {issue_key}: {e}")
141
153
  return json.dumps({"error": str(e)})
154
+
155
+ def add_worklog(self, issue_key: str, time_spent: str, comment: Optional[str] = None) -> str:
156
+ """
157
+ Adds a worklog entry to log time spent on a specific Jira issue.
158
+
159
+ :param issue_key: The key of the issue to log work against (e.g., 'PROJ-123').
160
+ :param time_spent: The amount of time spent. Use Jira's format, e.g., '2h', '30m', '1d 4h'.
161
+ :param comment: An optional comment describing the work done.
162
+ :return: A JSON string indicating success or containing an error message.
163
+ """
164
+ try:
165
+ self.jira.add_worklog(issue=issue_key, timeSpent=time_spent, comment=comment)
166
+ log_debug(f"Worklog of '{time_spent}' added to issue {issue_key}")
167
+ return json.dumps({"status": "success", "issue_key": issue_key, "time_spent": time_spent})
168
+ except Exception as e:
169
+ logger.error(f"Error adding worklog to issue {issue_key}: {e}")
170
+ return json.dumps({"error": str(e)})