agno 2.2.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (575) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +51 -0
  3. agno/agent/agent.py +10405 -0
  4. agno/api/__init__.py +0 -0
  5. agno/api/agent.py +28 -0
  6. agno/api/api.py +40 -0
  7. agno/api/evals.py +22 -0
  8. agno/api/os.py +17 -0
  9. agno/api/routes.py +13 -0
  10. agno/api/schemas/__init__.py +9 -0
  11. agno/api/schemas/agent.py +16 -0
  12. agno/api/schemas/evals.py +16 -0
  13. agno/api/schemas/os.py +14 -0
  14. agno/api/schemas/response.py +6 -0
  15. agno/api/schemas/team.py +16 -0
  16. agno/api/schemas/utils.py +21 -0
  17. agno/api/schemas/workflows.py +16 -0
  18. agno/api/settings.py +53 -0
  19. agno/api/team.py +30 -0
  20. agno/api/workflow.py +28 -0
  21. agno/cloud/aws/base.py +214 -0
  22. agno/cloud/aws/s3/__init__.py +2 -0
  23. agno/cloud/aws/s3/api_client.py +43 -0
  24. agno/cloud/aws/s3/bucket.py +195 -0
  25. agno/cloud/aws/s3/object.py +57 -0
  26. agno/culture/__init__.py +3 -0
  27. agno/culture/manager.py +956 -0
  28. agno/db/__init__.py +24 -0
  29. agno/db/async_postgres/__init__.py +3 -0
  30. agno/db/base.py +598 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2042 -0
  33. agno/db/dynamo/schemas.py +314 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +1795 -0
  37. agno/db/firestore/schemas.py +140 -0
  38. agno/db/firestore/utils.py +376 -0
  39. agno/db/gcs_json/__init__.py +3 -0
  40. agno/db/gcs_json/gcs_json_db.py +1335 -0
  41. agno/db/gcs_json/utils.py +228 -0
  42. agno/db/in_memory/__init__.py +3 -0
  43. agno/db/in_memory/in_memory_db.py +1160 -0
  44. agno/db/in_memory/utils.py +230 -0
  45. agno/db/json/__init__.py +3 -0
  46. agno/db/json/json_db.py +1328 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/__init__.py +0 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/mongo/__init__.py +17 -0
  51. agno/db/mongo/async_mongo.py +2026 -0
  52. agno/db/mongo/mongo.py +1982 -0
  53. agno/db/mongo/schemas.py +87 -0
  54. agno/db/mongo/utils.py +259 -0
  55. agno/db/mysql/__init__.py +3 -0
  56. agno/db/mysql/mysql.py +2308 -0
  57. agno/db/mysql/schemas.py +138 -0
  58. agno/db/mysql/utils.py +355 -0
  59. agno/db/postgres/__init__.py +4 -0
  60. agno/db/postgres/async_postgres.py +1927 -0
  61. agno/db/postgres/postgres.py +2260 -0
  62. agno/db/postgres/schemas.py +139 -0
  63. agno/db/postgres/utils.py +442 -0
  64. agno/db/redis/__init__.py +3 -0
  65. agno/db/redis/redis.py +1660 -0
  66. agno/db/redis/schemas.py +123 -0
  67. agno/db/redis/utils.py +346 -0
  68. agno/db/schemas/__init__.py +4 -0
  69. agno/db/schemas/culture.py +120 -0
  70. agno/db/schemas/evals.py +33 -0
  71. agno/db/schemas/knowledge.py +40 -0
  72. agno/db/schemas/memory.py +46 -0
  73. agno/db/schemas/metrics.py +0 -0
  74. agno/db/singlestore/__init__.py +3 -0
  75. agno/db/singlestore/schemas.py +130 -0
  76. agno/db/singlestore/singlestore.py +2272 -0
  77. agno/db/singlestore/utils.py +384 -0
  78. agno/db/sqlite/__init__.py +4 -0
  79. agno/db/sqlite/async_sqlite.py +2293 -0
  80. agno/db/sqlite/schemas.py +133 -0
  81. agno/db/sqlite/sqlite.py +2288 -0
  82. agno/db/sqlite/utils.py +431 -0
  83. agno/db/surrealdb/__init__.py +3 -0
  84. agno/db/surrealdb/metrics.py +292 -0
  85. agno/db/surrealdb/models.py +309 -0
  86. agno/db/surrealdb/queries.py +71 -0
  87. agno/db/surrealdb/surrealdb.py +1353 -0
  88. agno/db/surrealdb/utils.py +147 -0
  89. agno/db/utils.py +116 -0
  90. agno/debug.py +18 -0
  91. agno/eval/__init__.py +14 -0
  92. agno/eval/accuracy.py +834 -0
  93. agno/eval/performance.py +773 -0
  94. agno/eval/reliability.py +306 -0
  95. agno/eval/utils.py +119 -0
  96. agno/exceptions.py +161 -0
  97. agno/filters.py +354 -0
  98. agno/guardrails/__init__.py +6 -0
  99. agno/guardrails/base.py +19 -0
  100. agno/guardrails/openai.py +144 -0
  101. agno/guardrails/pii.py +94 -0
  102. agno/guardrails/prompt_injection.py +52 -0
  103. agno/integrations/__init__.py +0 -0
  104. agno/integrations/discord/__init__.py +3 -0
  105. agno/integrations/discord/client.py +203 -0
  106. agno/knowledge/__init__.py +5 -0
  107. agno/knowledge/chunking/__init__.py +0 -0
  108. agno/knowledge/chunking/agentic.py +79 -0
  109. agno/knowledge/chunking/document.py +91 -0
  110. agno/knowledge/chunking/fixed.py +57 -0
  111. agno/knowledge/chunking/markdown.py +151 -0
  112. agno/knowledge/chunking/recursive.py +63 -0
  113. agno/knowledge/chunking/row.py +39 -0
  114. agno/knowledge/chunking/semantic.py +86 -0
  115. agno/knowledge/chunking/strategy.py +165 -0
  116. agno/knowledge/content.py +74 -0
  117. agno/knowledge/document/__init__.py +5 -0
  118. agno/knowledge/document/base.py +58 -0
  119. agno/knowledge/embedder/__init__.py +5 -0
  120. agno/knowledge/embedder/aws_bedrock.py +343 -0
  121. agno/knowledge/embedder/azure_openai.py +210 -0
  122. agno/knowledge/embedder/base.py +23 -0
  123. agno/knowledge/embedder/cohere.py +323 -0
  124. agno/knowledge/embedder/fastembed.py +62 -0
  125. agno/knowledge/embedder/fireworks.py +13 -0
  126. agno/knowledge/embedder/google.py +258 -0
  127. agno/knowledge/embedder/huggingface.py +94 -0
  128. agno/knowledge/embedder/jina.py +182 -0
  129. agno/knowledge/embedder/langdb.py +22 -0
  130. agno/knowledge/embedder/mistral.py +206 -0
  131. agno/knowledge/embedder/nebius.py +13 -0
  132. agno/knowledge/embedder/ollama.py +154 -0
  133. agno/knowledge/embedder/openai.py +195 -0
  134. agno/knowledge/embedder/sentence_transformer.py +63 -0
  135. agno/knowledge/embedder/together.py +13 -0
  136. agno/knowledge/embedder/vllm.py +262 -0
  137. agno/knowledge/embedder/voyageai.py +165 -0
  138. agno/knowledge/knowledge.py +1988 -0
  139. agno/knowledge/reader/__init__.py +7 -0
  140. agno/knowledge/reader/arxiv_reader.py +81 -0
  141. agno/knowledge/reader/base.py +95 -0
  142. agno/knowledge/reader/csv_reader.py +166 -0
  143. agno/knowledge/reader/docx_reader.py +82 -0
  144. agno/knowledge/reader/field_labeled_csv_reader.py +292 -0
  145. agno/knowledge/reader/firecrawl_reader.py +201 -0
  146. agno/knowledge/reader/json_reader.py +87 -0
  147. agno/knowledge/reader/markdown_reader.py +137 -0
  148. agno/knowledge/reader/pdf_reader.py +431 -0
  149. agno/knowledge/reader/pptx_reader.py +101 -0
  150. agno/knowledge/reader/reader_factory.py +313 -0
  151. agno/knowledge/reader/s3_reader.py +89 -0
  152. agno/knowledge/reader/tavily_reader.py +194 -0
  153. agno/knowledge/reader/text_reader.py +115 -0
  154. agno/knowledge/reader/web_search_reader.py +372 -0
  155. agno/knowledge/reader/website_reader.py +455 -0
  156. agno/knowledge/reader/wikipedia_reader.py +59 -0
  157. agno/knowledge/reader/youtube_reader.py +78 -0
  158. agno/knowledge/remote_content/__init__.py +0 -0
  159. agno/knowledge/remote_content/remote_content.py +88 -0
  160. agno/knowledge/reranker/__init__.py +3 -0
  161. agno/knowledge/reranker/base.py +14 -0
  162. agno/knowledge/reranker/cohere.py +64 -0
  163. agno/knowledge/reranker/infinity.py +195 -0
  164. agno/knowledge/reranker/sentence_transformer.py +54 -0
  165. agno/knowledge/types.py +39 -0
  166. agno/knowledge/utils.py +189 -0
  167. agno/media.py +462 -0
  168. agno/memory/__init__.py +3 -0
  169. agno/memory/manager.py +1327 -0
  170. agno/models/__init__.py +0 -0
  171. agno/models/aimlapi/__init__.py +5 -0
  172. agno/models/aimlapi/aimlapi.py +45 -0
  173. agno/models/anthropic/__init__.py +5 -0
  174. agno/models/anthropic/claude.py +757 -0
  175. agno/models/aws/__init__.py +15 -0
  176. agno/models/aws/bedrock.py +701 -0
  177. agno/models/aws/claude.py +378 -0
  178. agno/models/azure/__init__.py +18 -0
  179. agno/models/azure/ai_foundry.py +485 -0
  180. agno/models/azure/openai_chat.py +131 -0
  181. agno/models/base.py +2175 -0
  182. agno/models/cerebras/__init__.py +12 -0
  183. agno/models/cerebras/cerebras.py +501 -0
  184. agno/models/cerebras/cerebras_openai.py +112 -0
  185. agno/models/cohere/__init__.py +5 -0
  186. agno/models/cohere/chat.py +389 -0
  187. agno/models/cometapi/__init__.py +5 -0
  188. agno/models/cometapi/cometapi.py +57 -0
  189. agno/models/dashscope/__init__.py +5 -0
  190. agno/models/dashscope/dashscope.py +91 -0
  191. agno/models/deepinfra/__init__.py +5 -0
  192. agno/models/deepinfra/deepinfra.py +28 -0
  193. agno/models/deepseek/__init__.py +5 -0
  194. agno/models/deepseek/deepseek.py +61 -0
  195. agno/models/defaults.py +1 -0
  196. agno/models/fireworks/__init__.py +5 -0
  197. agno/models/fireworks/fireworks.py +26 -0
  198. agno/models/google/__init__.py +5 -0
  199. agno/models/google/gemini.py +1085 -0
  200. agno/models/groq/__init__.py +5 -0
  201. agno/models/groq/groq.py +556 -0
  202. agno/models/huggingface/__init__.py +5 -0
  203. agno/models/huggingface/huggingface.py +491 -0
  204. agno/models/ibm/__init__.py +5 -0
  205. agno/models/ibm/watsonx.py +422 -0
  206. agno/models/internlm/__init__.py +3 -0
  207. agno/models/internlm/internlm.py +26 -0
  208. agno/models/langdb/__init__.py +1 -0
  209. agno/models/langdb/langdb.py +48 -0
  210. agno/models/litellm/__init__.py +14 -0
  211. agno/models/litellm/chat.py +468 -0
  212. agno/models/litellm/litellm_openai.py +25 -0
  213. agno/models/llama_cpp/__init__.py +5 -0
  214. agno/models/llama_cpp/llama_cpp.py +22 -0
  215. agno/models/lmstudio/__init__.py +5 -0
  216. agno/models/lmstudio/lmstudio.py +25 -0
  217. agno/models/message.py +434 -0
  218. agno/models/meta/__init__.py +12 -0
  219. agno/models/meta/llama.py +475 -0
  220. agno/models/meta/llama_openai.py +78 -0
  221. agno/models/metrics.py +120 -0
  222. agno/models/mistral/__init__.py +5 -0
  223. agno/models/mistral/mistral.py +432 -0
  224. agno/models/nebius/__init__.py +3 -0
  225. agno/models/nebius/nebius.py +54 -0
  226. agno/models/nexus/__init__.py +3 -0
  227. agno/models/nexus/nexus.py +22 -0
  228. agno/models/nvidia/__init__.py +5 -0
  229. agno/models/nvidia/nvidia.py +28 -0
  230. agno/models/ollama/__init__.py +5 -0
  231. agno/models/ollama/chat.py +441 -0
  232. agno/models/openai/__init__.py +9 -0
  233. agno/models/openai/chat.py +883 -0
  234. agno/models/openai/like.py +27 -0
  235. agno/models/openai/responses.py +1050 -0
  236. agno/models/openrouter/__init__.py +5 -0
  237. agno/models/openrouter/openrouter.py +66 -0
  238. agno/models/perplexity/__init__.py +5 -0
  239. agno/models/perplexity/perplexity.py +187 -0
  240. agno/models/portkey/__init__.py +3 -0
  241. agno/models/portkey/portkey.py +81 -0
  242. agno/models/requesty/__init__.py +5 -0
  243. agno/models/requesty/requesty.py +52 -0
  244. agno/models/response.py +199 -0
  245. agno/models/sambanova/__init__.py +5 -0
  246. agno/models/sambanova/sambanova.py +28 -0
  247. agno/models/siliconflow/__init__.py +5 -0
  248. agno/models/siliconflow/siliconflow.py +25 -0
  249. agno/models/together/__init__.py +5 -0
  250. agno/models/together/together.py +25 -0
  251. agno/models/utils.py +266 -0
  252. agno/models/vercel/__init__.py +3 -0
  253. agno/models/vercel/v0.py +26 -0
  254. agno/models/vertexai/__init__.py +0 -0
  255. agno/models/vertexai/claude.py +70 -0
  256. agno/models/vllm/__init__.py +3 -0
  257. agno/models/vllm/vllm.py +78 -0
  258. agno/models/xai/__init__.py +3 -0
  259. agno/models/xai/xai.py +113 -0
  260. agno/os/__init__.py +3 -0
  261. agno/os/app.py +876 -0
  262. agno/os/auth.py +57 -0
  263. agno/os/config.py +104 -0
  264. agno/os/interfaces/__init__.py +1 -0
  265. agno/os/interfaces/a2a/__init__.py +3 -0
  266. agno/os/interfaces/a2a/a2a.py +42 -0
  267. agno/os/interfaces/a2a/router.py +250 -0
  268. agno/os/interfaces/a2a/utils.py +924 -0
  269. agno/os/interfaces/agui/__init__.py +3 -0
  270. agno/os/interfaces/agui/agui.py +47 -0
  271. agno/os/interfaces/agui/router.py +144 -0
  272. agno/os/interfaces/agui/utils.py +534 -0
  273. agno/os/interfaces/base.py +25 -0
  274. agno/os/interfaces/slack/__init__.py +3 -0
  275. agno/os/interfaces/slack/router.py +148 -0
  276. agno/os/interfaces/slack/security.py +30 -0
  277. agno/os/interfaces/slack/slack.py +47 -0
  278. agno/os/interfaces/whatsapp/__init__.py +3 -0
  279. agno/os/interfaces/whatsapp/router.py +211 -0
  280. agno/os/interfaces/whatsapp/security.py +53 -0
  281. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  282. agno/os/mcp.py +292 -0
  283. agno/os/middleware/__init__.py +7 -0
  284. agno/os/middleware/jwt.py +233 -0
  285. agno/os/router.py +1763 -0
  286. agno/os/routers/__init__.py +3 -0
  287. agno/os/routers/evals/__init__.py +3 -0
  288. agno/os/routers/evals/evals.py +430 -0
  289. agno/os/routers/evals/schemas.py +142 -0
  290. agno/os/routers/evals/utils.py +162 -0
  291. agno/os/routers/health.py +31 -0
  292. agno/os/routers/home.py +52 -0
  293. agno/os/routers/knowledge/__init__.py +3 -0
  294. agno/os/routers/knowledge/knowledge.py +997 -0
  295. agno/os/routers/knowledge/schemas.py +178 -0
  296. agno/os/routers/memory/__init__.py +3 -0
  297. agno/os/routers/memory/memory.py +515 -0
  298. agno/os/routers/memory/schemas.py +62 -0
  299. agno/os/routers/metrics/__init__.py +3 -0
  300. agno/os/routers/metrics/metrics.py +190 -0
  301. agno/os/routers/metrics/schemas.py +47 -0
  302. agno/os/routers/session/__init__.py +3 -0
  303. agno/os/routers/session/session.py +997 -0
  304. agno/os/schema.py +1055 -0
  305. agno/os/settings.py +43 -0
  306. agno/os/utils.py +630 -0
  307. agno/py.typed +0 -0
  308. agno/reasoning/__init__.py +0 -0
  309. agno/reasoning/anthropic.py +80 -0
  310. agno/reasoning/azure_ai_foundry.py +67 -0
  311. agno/reasoning/deepseek.py +63 -0
  312. agno/reasoning/default.py +97 -0
  313. agno/reasoning/gemini.py +73 -0
  314. agno/reasoning/groq.py +71 -0
  315. agno/reasoning/helpers.py +63 -0
  316. agno/reasoning/ollama.py +67 -0
  317. agno/reasoning/openai.py +86 -0
  318. agno/reasoning/step.py +31 -0
  319. agno/reasoning/vertexai.py +76 -0
  320. agno/run/__init__.py +6 -0
  321. agno/run/agent.py +787 -0
  322. agno/run/base.py +229 -0
  323. agno/run/cancel.py +81 -0
  324. agno/run/messages.py +32 -0
  325. agno/run/team.py +753 -0
  326. agno/run/workflow.py +708 -0
  327. agno/session/__init__.py +10 -0
  328. agno/session/agent.py +295 -0
  329. agno/session/summary.py +265 -0
  330. agno/session/team.py +392 -0
  331. agno/session/workflow.py +205 -0
  332. agno/team/__init__.py +37 -0
  333. agno/team/team.py +8793 -0
  334. agno/tools/__init__.py +10 -0
  335. agno/tools/agentql.py +120 -0
  336. agno/tools/airflow.py +69 -0
  337. agno/tools/api.py +122 -0
  338. agno/tools/apify.py +314 -0
  339. agno/tools/arxiv.py +127 -0
  340. agno/tools/aws_lambda.py +53 -0
  341. agno/tools/aws_ses.py +66 -0
  342. agno/tools/baidusearch.py +89 -0
  343. agno/tools/bitbucket.py +292 -0
  344. agno/tools/brandfetch.py +213 -0
  345. agno/tools/bravesearch.py +106 -0
  346. agno/tools/brightdata.py +367 -0
  347. agno/tools/browserbase.py +209 -0
  348. agno/tools/calcom.py +255 -0
  349. agno/tools/calculator.py +151 -0
  350. agno/tools/cartesia.py +187 -0
  351. agno/tools/clickup.py +244 -0
  352. agno/tools/confluence.py +240 -0
  353. agno/tools/crawl4ai.py +158 -0
  354. agno/tools/csv_toolkit.py +185 -0
  355. agno/tools/dalle.py +110 -0
  356. agno/tools/daytona.py +475 -0
  357. agno/tools/decorator.py +262 -0
  358. agno/tools/desi_vocal.py +108 -0
  359. agno/tools/discord.py +161 -0
  360. agno/tools/docker.py +716 -0
  361. agno/tools/duckdb.py +379 -0
  362. agno/tools/duckduckgo.py +91 -0
  363. agno/tools/e2b.py +703 -0
  364. agno/tools/eleven_labs.py +196 -0
  365. agno/tools/email.py +67 -0
  366. agno/tools/evm.py +129 -0
  367. agno/tools/exa.py +396 -0
  368. agno/tools/fal.py +127 -0
  369. agno/tools/file.py +240 -0
  370. agno/tools/file_generation.py +350 -0
  371. agno/tools/financial_datasets.py +288 -0
  372. agno/tools/firecrawl.py +143 -0
  373. agno/tools/function.py +1187 -0
  374. agno/tools/giphy.py +93 -0
  375. agno/tools/github.py +1760 -0
  376. agno/tools/gmail.py +922 -0
  377. agno/tools/google_bigquery.py +117 -0
  378. agno/tools/google_drive.py +270 -0
  379. agno/tools/google_maps.py +253 -0
  380. agno/tools/googlecalendar.py +674 -0
  381. agno/tools/googlesearch.py +98 -0
  382. agno/tools/googlesheets.py +377 -0
  383. agno/tools/hackernews.py +77 -0
  384. agno/tools/jina.py +101 -0
  385. agno/tools/jira.py +170 -0
  386. agno/tools/knowledge.py +218 -0
  387. agno/tools/linear.py +426 -0
  388. agno/tools/linkup.py +58 -0
  389. agno/tools/local_file_system.py +90 -0
  390. agno/tools/lumalab.py +183 -0
  391. agno/tools/mcp/__init__.py +10 -0
  392. agno/tools/mcp/mcp.py +331 -0
  393. agno/tools/mcp/multi_mcp.py +347 -0
  394. agno/tools/mcp/params.py +24 -0
  395. agno/tools/mcp_toolbox.py +284 -0
  396. agno/tools/mem0.py +193 -0
  397. agno/tools/memori.py +339 -0
  398. agno/tools/memory.py +419 -0
  399. agno/tools/mlx_transcribe.py +139 -0
  400. agno/tools/models/__init__.py +0 -0
  401. agno/tools/models/azure_openai.py +190 -0
  402. agno/tools/models/gemini.py +203 -0
  403. agno/tools/models/groq.py +158 -0
  404. agno/tools/models/morph.py +186 -0
  405. agno/tools/models/nebius.py +124 -0
  406. agno/tools/models_labs.py +195 -0
  407. agno/tools/moviepy_video.py +349 -0
  408. agno/tools/neo4j.py +134 -0
  409. agno/tools/newspaper.py +46 -0
  410. agno/tools/newspaper4k.py +93 -0
  411. agno/tools/notion.py +204 -0
  412. agno/tools/openai.py +202 -0
  413. agno/tools/openbb.py +160 -0
  414. agno/tools/opencv.py +321 -0
  415. agno/tools/openweather.py +233 -0
  416. agno/tools/oxylabs.py +385 -0
  417. agno/tools/pandas.py +102 -0
  418. agno/tools/parallel.py +314 -0
  419. agno/tools/postgres.py +257 -0
  420. agno/tools/pubmed.py +188 -0
  421. agno/tools/python.py +205 -0
  422. agno/tools/reasoning.py +283 -0
  423. agno/tools/reddit.py +467 -0
  424. agno/tools/replicate.py +117 -0
  425. agno/tools/resend.py +62 -0
  426. agno/tools/scrapegraph.py +222 -0
  427. agno/tools/searxng.py +152 -0
  428. agno/tools/serpapi.py +116 -0
  429. agno/tools/serper.py +255 -0
  430. agno/tools/shell.py +53 -0
  431. agno/tools/slack.py +136 -0
  432. agno/tools/sleep.py +20 -0
  433. agno/tools/spider.py +116 -0
  434. agno/tools/sql.py +154 -0
  435. agno/tools/streamlit/__init__.py +0 -0
  436. agno/tools/streamlit/components.py +113 -0
  437. agno/tools/tavily.py +254 -0
  438. agno/tools/telegram.py +48 -0
  439. agno/tools/todoist.py +218 -0
  440. agno/tools/tool_registry.py +1 -0
  441. agno/tools/toolkit.py +146 -0
  442. agno/tools/trafilatura.py +388 -0
  443. agno/tools/trello.py +274 -0
  444. agno/tools/twilio.py +186 -0
  445. agno/tools/user_control_flow.py +78 -0
  446. agno/tools/valyu.py +228 -0
  447. agno/tools/visualization.py +467 -0
  448. agno/tools/webbrowser.py +28 -0
  449. agno/tools/webex.py +76 -0
  450. agno/tools/website.py +54 -0
  451. agno/tools/webtools.py +45 -0
  452. agno/tools/whatsapp.py +286 -0
  453. agno/tools/wikipedia.py +63 -0
  454. agno/tools/workflow.py +278 -0
  455. agno/tools/x.py +335 -0
  456. agno/tools/yfinance.py +257 -0
  457. agno/tools/youtube.py +184 -0
  458. agno/tools/zendesk.py +82 -0
  459. agno/tools/zep.py +454 -0
  460. agno/tools/zoom.py +382 -0
  461. agno/utils/__init__.py +0 -0
  462. agno/utils/agent.py +820 -0
  463. agno/utils/audio.py +49 -0
  464. agno/utils/certs.py +27 -0
  465. agno/utils/code_execution.py +11 -0
  466. agno/utils/common.py +132 -0
  467. agno/utils/dttm.py +13 -0
  468. agno/utils/enum.py +22 -0
  469. agno/utils/env.py +11 -0
  470. agno/utils/events.py +696 -0
  471. agno/utils/format_str.py +16 -0
  472. agno/utils/functions.py +166 -0
  473. agno/utils/gemini.py +426 -0
  474. agno/utils/hooks.py +57 -0
  475. agno/utils/http.py +74 -0
  476. agno/utils/json_schema.py +234 -0
  477. agno/utils/knowledge.py +36 -0
  478. agno/utils/location.py +19 -0
  479. agno/utils/log.py +255 -0
  480. agno/utils/mcp.py +214 -0
  481. agno/utils/media.py +352 -0
  482. agno/utils/merge_dict.py +41 -0
  483. agno/utils/message.py +118 -0
  484. agno/utils/models/__init__.py +0 -0
  485. agno/utils/models/ai_foundry.py +43 -0
  486. agno/utils/models/claude.py +358 -0
  487. agno/utils/models/cohere.py +87 -0
  488. agno/utils/models/llama.py +78 -0
  489. agno/utils/models/mistral.py +98 -0
  490. agno/utils/models/openai_responses.py +140 -0
  491. agno/utils/models/schema_utils.py +153 -0
  492. agno/utils/models/watsonx.py +41 -0
  493. agno/utils/openai.py +257 -0
  494. agno/utils/pickle.py +32 -0
  495. agno/utils/pprint.py +178 -0
  496. agno/utils/print_response/__init__.py +0 -0
  497. agno/utils/print_response/agent.py +842 -0
  498. agno/utils/print_response/team.py +1724 -0
  499. agno/utils/print_response/workflow.py +1668 -0
  500. agno/utils/prompts.py +111 -0
  501. agno/utils/reasoning.py +108 -0
  502. agno/utils/response.py +163 -0
  503. agno/utils/response_iterator.py +17 -0
  504. agno/utils/safe_formatter.py +24 -0
  505. agno/utils/serialize.py +32 -0
  506. agno/utils/shell.py +22 -0
  507. agno/utils/streamlit.py +487 -0
  508. agno/utils/string.py +231 -0
  509. agno/utils/team.py +139 -0
  510. agno/utils/timer.py +41 -0
  511. agno/utils/tools.py +102 -0
  512. agno/utils/web.py +23 -0
  513. agno/utils/whatsapp.py +305 -0
  514. agno/utils/yaml_io.py +25 -0
  515. agno/vectordb/__init__.py +3 -0
  516. agno/vectordb/base.py +127 -0
  517. agno/vectordb/cassandra/__init__.py +5 -0
  518. agno/vectordb/cassandra/cassandra.py +501 -0
  519. agno/vectordb/cassandra/extra_param_mixin.py +11 -0
  520. agno/vectordb/cassandra/index.py +13 -0
  521. agno/vectordb/chroma/__init__.py +5 -0
  522. agno/vectordb/chroma/chromadb.py +929 -0
  523. agno/vectordb/clickhouse/__init__.py +9 -0
  524. agno/vectordb/clickhouse/clickhousedb.py +835 -0
  525. agno/vectordb/clickhouse/index.py +9 -0
  526. agno/vectordb/couchbase/__init__.py +3 -0
  527. agno/vectordb/couchbase/couchbase.py +1442 -0
  528. agno/vectordb/distance.py +7 -0
  529. agno/vectordb/lancedb/__init__.py +6 -0
  530. agno/vectordb/lancedb/lance_db.py +995 -0
  531. agno/vectordb/langchaindb/__init__.py +5 -0
  532. agno/vectordb/langchaindb/langchaindb.py +163 -0
  533. agno/vectordb/lightrag/__init__.py +5 -0
  534. agno/vectordb/lightrag/lightrag.py +388 -0
  535. agno/vectordb/llamaindex/__init__.py +3 -0
  536. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  537. agno/vectordb/milvus/__init__.py +4 -0
  538. agno/vectordb/milvus/milvus.py +1182 -0
  539. agno/vectordb/mongodb/__init__.py +9 -0
  540. agno/vectordb/mongodb/mongodb.py +1417 -0
  541. agno/vectordb/pgvector/__init__.py +12 -0
  542. agno/vectordb/pgvector/index.py +23 -0
  543. agno/vectordb/pgvector/pgvector.py +1462 -0
  544. agno/vectordb/pineconedb/__init__.py +5 -0
  545. agno/vectordb/pineconedb/pineconedb.py +747 -0
  546. agno/vectordb/qdrant/__init__.py +5 -0
  547. agno/vectordb/qdrant/qdrant.py +1134 -0
  548. agno/vectordb/redis/__init__.py +9 -0
  549. agno/vectordb/redis/redisdb.py +694 -0
  550. agno/vectordb/search.py +7 -0
  551. agno/vectordb/singlestore/__init__.py +10 -0
  552. agno/vectordb/singlestore/index.py +41 -0
  553. agno/vectordb/singlestore/singlestore.py +763 -0
  554. agno/vectordb/surrealdb/__init__.py +3 -0
  555. agno/vectordb/surrealdb/surrealdb.py +699 -0
  556. agno/vectordb/upstashdb/__init__.py +5 -0
  557. agno/vectordb/upstashdb/upstashdb.py +718 -0
  558. agno/vectordb/weaviate/__init__.py +8 -0
  559. agno/vectordb/weaviate/index.py +15 -0
  560. agno/vectordb/weaviate/weaviate.py +1005 -0
  561. agno/workflow/__init__.py +23 -0
  562. agno/workflow/agent.py +299 -0
  563. agno/workflow/condition.py +738 -0
  564. agno/workflow/loop.py +735 -0
  565. agno/workflow/parallel.py +824 -0
  566. agno/workflow/router.py +702 -0
  567. agno/workflow/step.py +1432 -0
  568. agno/workflow/steps.py +592 -0
  569. agno/workflow/types.py +520 -0
  570. agno/workflow/workflow.py +4321 -0
  571. agno-2.2.13.dist-info/METADATA +614 -0
  572. agno-2.2.13.dist-info/RECORD +575 -0
  573. agno-2.2.13.dist-info/WHEEL +5 -0
  574. agno-2.2.13.dist-info/licenses/LICENSE +201 -0
  575. agno-2.2.13.dist-info/top_level.txt +1 -0
@@ -0,0 +1,98 @@
1
+ import json
2
+ from typing import Any, Dict, List, Optional
3
+
4
+ from agno.tools import Toolkit
5
+ from agno.utils.log import log_debug
6
+
7
+ try:
8
+ from googlesearch import search
9
+ except ImportError:
10
+ raise ImportError("`googlesearch-python` not installed. Please install using `pip install googlesearch-python`")
11
+
12
+ try:
13
+ from pycountry import pycountry
14
+ except ImportError:
15
+ raise ImportError("`pycountry` not installed. Please install using `pip install pycountry`")
16
+
17
+
18
+ class GoogleSearchTools(Toolkit):
19
+ """
20
+ GoogleSearch is a Python library for searching Google easily.
21
+ It uses requests and BeautifulSoup4 to scrape Google.
22
+
23
+ Args:
24
+ fixed_max_results (Optional[int]): A fixed number of maximum results.
25
+ fixed_language (Optional[str]): Language of the search results.
26
+ headers (Optional[Any]): Custom headers for the request.
27
+ proxy (Optional[str]): Proxy settings for the request.
28
+ timeout (Optional[int]): Timeout for the request, default is 10 seconds.
29
+ cache_results (bool): Enable caching of search results.
30
+ cache_ttl (int): Time-to-live for cached results in seconds.
31
+ cache_dir (Optional[str]): Directory to store cache files.
32
+ enable_google_search (bool): Enable Google search.
33
+ all (bool): Enable all tools.
34
+ """
35
+
36
+ def __init__(
37
+ self,
38
+ fixed_max_results: Optional[int] = None,
39
+ fixed_language: Optional[str] = None,
40
+ headers: Optional[Any] = None,
41
+ proxy: Optional[str] = None,
42
+ timeout: Optional[int] = 10,
43
+ enable_google_search: bool = True,
44
+ all: bool = False,
45
+ **kwargs,
46
+ ):
47
+ self.fixed_max_results: Optional[int] = fixed_max_results
48
+ self.fixed_language: Optional[str] = fixed_language
49
+ self.headers: Optional[Any] = headers
50
+ self.proxy: Optional[str] = proxy
51
+ self.timeout: Optional[int] = timeout
52
+
53
+ tools = []
54
+ if all or enable_google_search:
55
+ tools.append(self.google_search)
56
+
57
+ super().__init__(name="google_search_tools", tools=tools, **kwargs)
58
+
59
+ def google_search(self, query: str, max_results: int = 5, language: str = "en") -> str:
60
+ """
61
+ Use this function to search Google for a specified query.
62
+
63
+ Args:
64
+ query (str): The query to search for.
65
+ max_results (int, optional): The maximum number of results to return. Default is 5.
66
+ language (str, optional): The language of the search results. Default is "en".
67
+
68
+ Returns:
69
+ str: A JSON formatted string containing the search results.
70
+ """
71
+ max_results = self.fixed_max_results or max_results
72
+ language = self.fixed_language or language
73
+
74
+ # Resolve language to ISO 639-1 code if needed
75
+ if len(language) != 2:
76
+ _language = pycountry.languages.lookup(language)
77
+ if _language:
78
+ language = _language.alpha_2
79
+ else:
80
+ language = "en"
81
+
82
+ log_debug(f"Searching Google [{language}] for: {query}")
83
+
84
+ # Perform Google search using the googlesearch-python package
85
+ results = list(search(query, num_results=max_results, lang=language))
86
+
87
+ # Collect the search results
88
+ res: List[Dict[str, str]] = []
89
+ for result in results:
90
+ res.append(
91
+ {
92
+ "title": result.title,
93
+ "url": result.url,
94
+ "description": result.description,
95
+ }
96
+ )
97
+
98
+ return json.dumps(res, indent=2)
@@ -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}"
@@ -0,0 +1,77 @@
1
+ import json
2
+ from typing import Any, List
3
+
4
+ import httpx
5
+
6
+ from agno.tools import Toolkit
7
+ from agno.utils.log import log_debug, logger
8
+
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
+
20
+ def __init__(
21
+ self, enable_get_top_stories: bool = True, enable_get_user_details: bool = True, all: bool = False, **kwargs
22
+ ):
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)
28
+
29
+ super().__init__(name="hackers_news", tools=tools, **kwargs)
30
+
31
+ def get_top_hackernews_stories(self, num_stories: int = 10) -> str:
32
+ """Use this function to get top stories from Hacker News.
33
+
34
+ Args:
35
+ num_stories (int): Number of stories to return. Defaults to 10.
36
+
37
+ Returns:
38
+ str: JSON string of top stories.
39
+ """
40
+
41
+ log_debug(f"Getting top {num_stories} stories from Hacker News")
42
+ # Fetch top story IDs
43
+ response = httpx.get("https://hacker-news.firebaseio.com/v0/topstories.json")
44
+ story_ids = response.json()
45
+
46
+ # Fetch story details
47
+ stories = []
48
+ for story_id in story_ids[:num_stories]:
49
+ story_response = httpx.get(f"https://hacker-news.firebaseio.com/v0/item/{story_id}.json")
50
+ story = story_response.json()
51
+ story["username"] = story["by"]
52
+ stories.append(story)
53
+ return json.dumps(stories)
54
+
55
+ def get_user_details(self, username: str) -> str:
56
+ """Use this function to get the details of a Hacker News user using their username.
57
+
58
+ Args:
59
+ username (str): Username of the user to get details for.
60
+
61
+ Returns:
62
+ str: JSON string of the user details.
63
+ """
64
+
65
+ try:
66
+ log_debug(f"Getting details for user: {username}")
67
+ user = httpx.get(f"https://hacker-news.firebaseio.com/v0/user/{username}.json").json()
68
+ user_details = {
69
+ "id": user.get("user_id"),
70
+ "karma": user.get("karma"),
71
+ "about": user.get("about"),
72
+ "total_items_submitted": len(user.get("submitted", [])),
73
+ }
74
+ return json.dumps(user_details)
75
+ except Exception as e:
76
+ logger.exception(e)
77
+ return f"Error getting user details: {e}"
agno/tools/jina.py ADDED
@@ -0,0 +1,101 @@
1
+ from os import getenv
2
+ from typing import Any, Dict, List, Optional
3
+
4
+ import httpx
5
+ from pydantic import BaseModel, Field, HttpUrl
6
+
7
+ from agno.tools import Toolkit
8
+ from agno.utils.log import logger
9
+
10
+
11
+ class JinaReaderToolsConfig(BaseModel):
12
+ api_key: Optional[str] = Field(None, description="API key for Jina Reader")
13
+ base_url: HttpUrl = Field("https://r.jina.ai/", description="Base URL for Jina Reader API") # type: ignore
14
+ search_url: HttpUrl = Field("https://s.jina.ai/", description="Search URL for Jina Reader API") # type: ignore
15
+ max_content_length: int = Field(10000, description="Maximum content length in characters")
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")
18
+
19
+
20
+ class JinaReaderTools(Toolkit):
21
+ def __init__(
22
+ self,
23
+ api_key: Optional[str] = getenv("JINA_API_KEY"),
24
+ base_url: str = "https://r.jina.ai/",
25
+ search_url: str = "https://s.jina.ai/",
26
+ max_content_length: int = 10000,
27
+ timeout: Optional[int] = None,
28
+ search_query_content: bool = True,
29
+ enable_read_url: bool = True,
30
+ enable_search_query: bool = False,
31
+ all: bool = False,
32
+ **kwargs,
33
+ ):
34
+ self.api_key = api_key or getenv("JINA_API_KEY")
35
+ self.config: JinaReaderToolsConfig = JinaReaderToolsConfig(
36
+ api_key=self.api_key,
37
+ base_url=base_url,
38
+ search_url=search_url,
39
+ max_content_length=max_content_length,
40
+ timeout=timeout,
41
+ search_query_content=search_query_content,
42
+ )
43
+
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)
51
+
52
+ def read_url(self, url: str) -> str:
53
+ """Reads a URL and returns the truncated content using Jina Reader API."""
54
+ full_url = f"{self.config.base_url}{url}"
55
+ try:
56
+ response = httpx.get(full_url, headers=self._get_headers())
57
+ response.raise_for_status()
58
+ content = response.json()
59
+ return self._truncate_content(str(content))
60
+ except Exception as e:
61
+ error_msg = f"Error reading URL: {str(e)}"
62
+ logger.error(error_msg)
63
+ return error_msg
64
+
65
+ def search_query(self, query: str) -> str:
66
+ """Performs a web search using Jina Reader API and returns the truncated results."""
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}
73
+ try:
74
+ response = httpx.post(full_url, headers=headers, json=body)
75
+ response.raise_for_status()
76
+ content = response.json()
77
+ return self._truncate_content(str(content))
78
+ except Exception as e:
79
+ error_msg = f"Error performing search: {str(e)}"
80
+ logger.error(error_msg)
81
+ return error_msg
82
+
83
+ def _get_headers(self) -> Dict[str, str]:
84
+ headers = {
85
+ "Accept": "application/json",
86
+ "X-With-Links-Summary": "true",
87
+ "X-With-Images-Summary": "true",
88
+ }
89
+ if self.config.api_key:
90
+ headers["Authorization"] = f"Bearer {self.config.api_key}"
91
+ if self.config.timeout:
92
+ headers["X-Timeout"] = str(self.config.timeout)
93
+
94
+ return headers
95
+
96
+ def _truncate_content(self, content: str) -> str:
97
+ """Truncate content to the maximum allowed length."""
98
+ if len(content) > self.config.max_content_length:
99
+ truncated = content[: self.config.max_content_length]
100
+ return truncated + "... (content truncated)"
101
+ return content