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,16 @@
1
+ from typing import Optional
2
+
3
+
4
+ def remove_indent(s: Optional[str]) -> Optional[str]:
5
+ """
6
+ Remove the indent from a string.
7
+
8
+ Args:
9
+ s (str): String to remove indent from
10
+
11
+ Returns:
12
+ str: String with indent removed
13
+ """
14
+ if s is not None and isinstance(s, str):
15
+ return "\n".join([line.strip() for line in s.split("\n")])
16
+ return None
@@ -0,0 +1,166 @@
1
+ import json
2
+ from typing import Any, Callable, Dict, Optional, TypeVar
3
+
4
+ from agno.tools.function import Function, FunctionCall
5
+ from agno.utils.log import log_debug, log_error
6
+
7
+ T = TypeVar("T")
8
+
9
+
10
+ def get_function_call(
11
+ name: str,
12
+ arguments: Optional[str] = None,
13
+ call_id: Optional[str] = None,
14
+ functions: Optional[Dict[str, Function]] = None,
15
+ ) -> Optional[FunctionCall]:
16
+ if functions is None:
17
+ return None
18
+
19
+ function_to_call: Optional[Function] = None
20
+ if name in functions:
21
+ function_to_call = functions[name]
22
+ if function_to_call is None:
23
+ log_error(f"Function {name} not found")
24
+ return None
25
+
26
+ function_call = FunctionCall(function=function_to_call)
27
+ if call_id is not None:
28
+ function_call.call_id = call_id
29
+ if arguments is not None and arguments != "":
30
+ try:
31
+ try:
32
+ _arguments = json.loads(arguments)
33
+ except Exception:
34
+ import ast
35
+
36
+ _arguments = ast.literal_eval(arguments)
37
+ except Exception as e:
38
+ log_error(f"Unable to decode function arguments:\n{arguments}\nError: {e}")
39
+ function_call.error = (
40
+ f"Error while decoding function arguments: {e}\n\n"
41
+ f"Please make sure we can json.loads() the arguments and retry."
42
+ )
43
+ return function_call
44
+
45
+ if not isinstance(_arguments, dict):
46
+ log_error(f"Function arguments are not a valid JSON object: {arguments}")
47
+ function_call.error = "Function arguments are not a valid JSON object.\n\n Please fix and retry."
48
+ return function_call
49
+
50
+ try:
51
+ clean_arguments: Dict[str, Any] = {}
52
+ for k, v in _arguments.items():
53
+ if isinstance(v, str):
54
+ _v = v.strip().lower()
55
+ if _v in ("none", "null"):
56
+ clean_arguments[k] = None
57
+ elif _v == "true":
58
+ clean_arguments[k] = True
59
+ elif _v == "false":
60
+ clean_arguments[k] = False
61
+ else:
62
+ clean_arguments[k] = v.strip()
63
+ else:
64
+ clean_arguments[k] = v
65
+
66
+ function_call.arguments = clean_arguments
67
+ except Exception as e:
68
+ log_error(f"Unable to parsing function arguments:\n{arguments}\nError: {e}")
69
+ function_call.error = f"Error while parsing function arguments: {e}\n\n Please fix and retry."
70
+ return function_call
71
+ return function_call
72
+
73
+
74
+ def cache_result(enable_cache: bool = True, cache_dir: Optional[str] = None, cache_ttl: int = 3600):
75
+ """
76
+ Decorator factory that creates a file-based caching decorator for function results.
77
+
78
+ Args:
79
+ enable_cache (bool): Enable caching of function results.
80
+ cache_dir (Optional[str]): Directory to store cache files. Defaults to system temp dir.
81
+ cache_ttl (int): Time-to-live for cached results in seconds.
82
+
83
+ Returns:
84
+ A decorator function that caches results on the filesystem.
85
+ """
86
+ import functools
87
+ import hashlib
88
+ import json
89
+ import os
90
+ import tempfile
91
+ import time
92
+
93
+ def decorator(func: Callable[..., T]) -> Callable[..., T]:
94
+ @functools.wraps(func)
95
+ def wrapper(*args, **kwargs):
96
+ # First argument might be 'self' but we don't need to handle it specially
97
+ instance = args[0] if args else None
98
+
99
+ # Skip caching if cache_results is False (only for class methods)
100
+ if instance and hasattr(instance, "cache_results") and not instance.cache_results:
101
+ return func(*args, **kwargs)
102
+
103
+ if not enable_cache:
104
+ return func(*args, **kwargs)
105
+
106
+ # Get cache directory
107
+ instance_cache_dir = (
108
+ getattr(instance, "cache_dir", cache_dir) if hasattr(instance, "cache_dir") else cache_dir
109
+ )
110
+ base_cache_dir = instance_cache_dir or os.path.join(tempfile.gettempdir(), "agno_cache")
111
+
112
+ # Create cache directory if it doesn't exist
113
+ func_cache_dir = os.path.join(base_cache_dir, func.__module__, func.__qualname__)
114
+ os.makedirs(func_cache_dir, exist_ok=True)
115
+
116
+ # Create a cache key using all arguments
117
+ # Convert args and kwargs to strings and join them
118
+ args_str = str(args)
119
+ kwargs_str = str(sorted(kwargs.items()))
120
+
121
+ # Create a hash for potentially large input
122
+ key_str = f"{func.__module__}.{func.__qualname__}:{args_str}:{kwargs_str}"
123
+ cache_key = hashlib.md5(key_str.encode()).hexdigest()
124
+
125
+ # Define cache file path
126
+ cache_file = os.path.join(func_cache_dir, f"{cache_key}.json")
127
+
128
+ # Check for cached result
129
+ if os.path.exists(cache_file):
130
+ try:
131
+ with open(cache_file, "r") as f:
132
+ cache_data = json.load(f)
133
+
134
+ timestamp = cache_data.get("timestamp", 0)
135
+ result = cache_data.get("result")
136
+
137
+ # Use instance ttl if available, otherwise use decorator ttl
138
+ effective_ttl = (
139
+ getattr(instance, "cache_ttl", cache_ttl) if hasattr(instance, "cache_ttl") else cache_ttl
140
+ )
141
+
142
+ if time.time() - timestamp <= effective_ttl:
143
+ log_debug(f"Cache hit for: {func.__name__}")
144
+ return result
145
+
146
+ # Remove expired entry
147
+ os.remove(cache_file)
148
+ except Exception as e:
149
+ log_error(f"Error reading cache: {e}")
150
+ # Continue with function execution if cache read fails
151
+
152
+ # Execute the function and cache the result
153
+ result = func(*args, **kwargs)
154
+
155
+ try:
156
+ with open(cache_file, "w") as f:
157
+ json.dump({"timestamp": time.time(), "result": result}, f)
158
+ except Exception as e:
159
+ log_error(f"Error writing cache: {e}")
160
+ # Continue even if cache write fails
161
+
162
+ return result
163
+
164
+ return wrapper
165
+
166
+ return decorator
agno/utils/gemini.py ADDED
@@ -0,0 +1,426 @@
1
+ from pathlib import Path
2
+ from typing import Any, Dict, List, Optional, Type, Union
3
+
4
+ from pydantic import BaseModel
5
+
6
+ from agno.media import Image
7
+ from agno.utils.log import log_error, log_warning
8
+
9
+ try:
10
+ from google.genai.types import (
11
+ FunctionDeclaration,
12
+ Schema,
13
+ Tool,
14
+ )
15
+ from google.genai.types import (
16
+ Type as GeminiType,
17
+ )
18
+ except ImportError:
19
+ raise ImportError("`google-genai` not installed. Please install it using `pip install google-genai`")
20
+
21
+
22
+ def prepare_response_schema(pydantic_model: Type[BaseModel]) -> Union[Type[BaseModel], Schema]:
23
+ """
24
+ Prepare a Pydantic model for use as Gemini response schema.
25
+
26
+ Returns the model directly if Gemini can handle it natively,
27
+ otherwise converts to Gemini's Schema format.
28
+
29
+ Args:
30
+ pydantic_model: A Pydantic model class
31
+
32
+ Returns:
33
+ Either the original Pydantic model or a converted Schema object
34
+ """
35
+ schema_dict = pydantic_model.model_json_schema()
36
+
37
+ # Convert to Gemini Schema if the model has problematic patterns
38
+ if needs_conversion(schema_dict):
39
+ try:
40
+ converted = convert_schema(schema_dict)
41
+ except Exception as e:
42
+ log_warning(f"Failed to convert schema for {pydantic_model}: {e}")
43
+ converted = None
44
+
45
+ if converted is None:
46
+ # If conversion fails, let Gemini handle it directly
47
+ return pydantic_model
48
+ return converted
49
+
50
+ # Gemini can handle this model directly
51
+ return pydantic_model
52
+
53
+
54
+ def needs_conversion(schema_dict: Dict[str, Any]) -> bool:
55
+ """
56
+ Check if a schema needs conversion for Gemini.
57
+
58
+ Returns True if the schema has:
59
+ - Self-references or circular references
60
+ - Dict fields (additionalProperties) that Gemini doesn't handle well
61
+ - Empty object definitions that Gemini rejects
62
+ """
63
+ # Check for dict fields (additionalProperties) anywhere in the schema
64
+ if has_additional_properties(schema_dict):
65
+ return True
66
+
67
+ # Check if schema has $defs with circular references
68
+ if "$defs" in schema_dict:
69
+ defs = schema_dict["$defs"]
70
+ for def_name, def_schema in defs.items():
71
+ ref_path = f"#/$defs/{def_name}"
72
+ if has_self_reference(def_schema, ref_path):
73
+ return True
74
+
75
+ return False
76
+
77
+
78
+ def has_additional_properties(schema: Any) -> bool:
79
+ """Check if schema has additionalProperties (Dict fields)"""
80
+ if isinstance(schema, dict):
81
+ # Direct check
82
+ if "additionalProperties" in schema:
83
+ return True
84
+
85
+ # Check properties recursively
86
+ if "properties" in schema:
87
+ for prop_schema in schema["properties"].values():
88
+ if has_additional_properties(prop_schema):
89
+ return True
90
+
91
+ # Check array items
92
+ if "items" in schema:
93
+ if has_additional_properties(schema["items"]):
94
+ return True
95
+
96
+ return False
97
+
98
+
99
+ def has_self_reference(schema: Dict, target_ref: str) -> bool:
100
+ """Check if a schema references itself (directly or indirectly)"""
101
+ if isinstance(schema, dict):
102
+ # Direct self-reference
103
+ if schema.get("$ref") == target_ref:
104
+ return True
105
+
106
+ # Check properties
107
+ if "properties" in schema:
108
+ for prop_schema in schema["properties"].values():
109
+ if has_self_reference(prop_schema, target_ref):
110
+ return True
111
+
112
+ # Check array items
113
+ if "items" in schema:
114
+ if has_self_reference(schema["items"], target_ref):
115
+ return True
116
+
117
+ # Check anyOf/oneOf/allOf
118
+ for key in ["anyOf", "oneOf", "allOf"]:
119
+ if key in schema:
120
+ for sub_schema in schema[key]:
121
+ if has_self_reference(sub_schema, target_ref):
122
+ return True
123
+
124
+ return False
125
+
126
+
127
+ def format_image_for_message(image: Image) -> Optional[Dict[str, Any]]:
128
+ # Case 1: Image is a URL
129
+ # Download the image from the URL and add it as base64 encoded data
130
+ if image.url is not None:
131
+ content_bytes = image.get_content_bytes() # type: ignore
132
+ if content_bytes is not None:
133
+ try:
134
+ import base64
135
+
136
+ image_data = {
137
+ "mime_type": "image/jpeg",
138
+ "data": base64.b64encode(content_bytes).decode("utf-8"),
139
+ }
140
+ return image_data
141
+ except Exception as e:
142
+ log_warning(f"Failed to download image from {image}: {e}")
143
+ return None
144
+ else:
145
+ log_warning(f"Unsupported image format: {image}")
146
+ return None
147
+
148
+ # Case 2: Image is a local path
149
+ elif image.filepath is not None:
150
+ try:
151
+ image_path = Path(image.filepath)
152
+ if image_path.exists() and image_path.is_file():
153
+ with open(image_path, "rb") as f:
154
+ content_bytes = f.read()
155
+ else:
156
+ log_error(f"Image file {image_path} does not exist.")
157
+ raise
158
+ return {
159
+ "mime_type": "image/jpeg",
160
+ "data": content_bytes,
161
+ }
162
+ except Exception as e:
163
+ log_warning(f"Failed to load image from {image.filepath}: {e}")
164
+ return None
165
+
166
+ # Case 3: Image is a bytes object
167
+ # Add it as base64 encoded data
168
+ elif image.content is not None and isinstance(image.content, bytes):
169
+ import base64
170
+
171
+ image_data = {"mime_type": "image/jpeg", "data": base64.b64encode(image.content).decode("utf-8")}
172
+ return image_data
173
+ else:
174
+ log_warning(f"Unknown image type: {type(image)}")
175
+ return None
176
+
177
+
178
+ def convert_schema(
179
+ schema_dict: Dict[str, Any], root_schema: Optional[Dict[str, Any]] = None, visited_refs: Optional[set] = None
180
+ ) -> Optional[Schema]:
181
+ """
182
+ Recursively convert a JSON-like schema dictionary to a types.Schema object.
183
+
184
+ Parameters:
185
+ schema_dict (dict): The JSON schema dictionary with keys like "type", "description",
186
+ "properties", and "required".
187
+ root_schema (dict, optional): The root schema containing $defs for resolving $ref
188
+ visited_refs (set, optional): Set of visited $ref paths to detect circular references
189
+
190
+ Returns:
191
+ types.Schema: The converted schema.
192
+ """
193
+
194
+ # If this is the initial call, set root_schema to self and initialize visited_refs
195
+ if root_schema is None:
196
+ root_schema = schema_dict
197
+ if visited_refs is None:
198
+ visited_refs = set()
199
+
200
+ # Handle $ref references with cycle detection
201
+ if "$ref" in schema_dict:
202
+ ref_path = schema_dict["$ref"]
203
+
204
+ # Check for circular reference
205
+ if ref_path in visited_refs:
206
+ # Return a basic object schema to break the cycle
207
+ return Schema(
208
+ type=GeminiType.OBJECT,
209
+ description=f"Circular reference to {ref_path}",
210
+ )
211
+
212
+ if ref_path.startswith("#/$defs/"):
213
+ def_name = ref_path.split("/")[-1]
214
+ if "$defs" in root_schema and def_name in root_schema["$defs"]:
215
+ # Add to visited set before recursing
216
+ new_visited = visited_refs.copy()
217
+ new_visited.add(ref_path)
218
+
219
+ referenced_schema = root_schema["$defs"][def_name]
220
+ return convert_schema(referenced_schema, root_schema, new_visited)
221
+ # If we can't resolve the reference, return None
222
+ return None
223
+
224
+ schema_type = schema_dict.get("type", "")
225
+ if schema_type is None or schema_type == "null":
226
+ return None
227
+ description = schema_dict.get("description", None)
228
+ title = schema_dict.get("title", None)
229
+ default = schema_dict.get("default", None)
230
+
231
+ # Handle enum types
232
+ if "enum" in schema_dict:
233
+ enum_values = schema_dict["enum"]
234
+ return Schema(type=GeminiType.STRING, enum=enum_values, description=description, default=default, title=title)
235
+
236
+ if schema_type == "object":
237
+ # Handle regular objects with properties
238
+ if "properties" in schema_dict:
239
+ properties = {}
240
+ for key, prop_def in schema_dict["properties"].items():
241
+ # Process nullable types
242
+ prop_type = prop_def.get("type", "")
243
+ is_nullable = False
244
+ if isinstance(prop_type, list) and "null" in prop_type:
245
+ prop_def["type"] = prop_type[0]
246
+ is_nullable = True
247
+
248
+ # Process property schema (pass root_schema and visited_refs for $ref resolution)
249
+ converted_schema = convert_schema(prop_def, root_schema, visited_refs)
250
+ if converted_schema is not None:
251
+ if is_nullable:
252
+ converted_schema.nullable = True
253
+ properties[key] = converted_schema
254
+ else:
255
+ properties[key] = Schema(
256
+ title=prop_def.get("title", None), description=prop_def.get("description", None)
257
+ )
258
+
259
+ required = schema_dict.get("required", [])
260
+
261
+ if properties:
262
+ return Schema(
263
+ type=GeminiType.OBJECT,
264
+ properties=properties,
265
+ required=required,
266
+ description=description,
267
+ default=default,
268
+ title=title,
269
+ )
270
+ else:
271
+ return Schema(type=GeminiType.OBJECT, description=description, default=default, title=title)
272
+
273
+ # Handle Dict types (objects with additionalProperties but no properties)
274
+ elif "additionalProperties" in schema_dict:
275
+ additional_props = schema_dict["additionalProperties"]
276
+
277
+ # If additionalProperties is a schema object (Dict[str, T] case)
278
+ if isinstance(additional_props, dict) and "type" in additional_props:
279
+ # For Gemini, we need to represent Dict[str, T] as an object with at least one property
280
+ # to avoid the "properties should be non-empty" error.
281
+ # We'll create a generic property that represents the dictionary structure
282
+
283
+ # Handle both single types and union types (arrays) from Zod schemas
284
+ type_value = additional_props.get("type", "string")
285
+ if isinstance(type_value, list):
286
+ value_type = type_value[0].upper() if type_value else "STRING"
287
+ union_types = ", ".join(type_value)
288
+ type_description_suffix = f" (supports union types: {union_types})"
289
+ else:
290
+ # Single type
291
+ value_type = type_value.upper()
292
+ type_description_suffix = ""
293
+
294
+ # Create a placeholder property to satisfy Gemini's requirements
295
+ # This is a workaround since Gemini doesn't support additionalProperties directly
296
+ placeholder_properties = {
297
+ "example_key": Schema(
298
+ type=value_type,
299
+ description=f"Example key-value pair. This object can contain any number of keys with {value_type.lower()} values{type_description_suffix}.",
300
+ )
301
+ }
302
+ if value_type == "ARRAY":
303
+ placeholder_properties["example_key"].items = {} # type: ignore
304
+
305
+ return Schema(
306
+ type=GeminiType.OBJECT,
307
+ properties=placeholder_properties,
308
+ description=description
309
+ or f"Dictionary with {value_type.lower()} values{type_description_suffix}. Can contain any number of key-value pairs.",
310
+ default=default,
311
+ )
312
+ else:
313
+ # additionalProperties is false or true
314
+ return Schema(type=GeminiType.OBJECT, description=description, default=default, title=title)
315
+
316
+ # Handle empty objects
317
+ else:
318
+ return Schema(type=GeminiType.OBJECT, description=description, default=default, title=title)
319
+
320
+ elif schema_type == "array" and "items" in schema_dict:
321
+ if not schema_dict["items"]: # Handle empty {}
322
+ items = Schema(type=GeminiType.STRING)
323
+ else:
324
+ converted_items = convert_schema(schema_dict["items"], root_schema, visited_refs)
325
+ items = converted_items if converted_items is not None else Schema(type=GeminiType.STRING)
326
+ min_items = schema_dict.get("minItems")
327
+ max_items = schema_dict.get("maxItems")
328
+ return Schema(
329
+ type=GeminiType.ARRAY,
330
+ description=description,
331
+ items=items,
332
+ min_items=min_items,
333
+ max_items=max_items,
334
+ title=title,
335
+ )
336
+
337
+ elif schema_type == "string":
338
+ schema_kwargs = {
339
+ "type": GeminiType.STRING,
340
+ "description": description,
341
+ "default": default,
342
+ "title": title,
343
+ }
344
+ if "format" in schema_dict:
345
+ schema_kwargs["format"] = schema_dict["format"]
346
+ return Schema(**schema_kwargs)
347
+
348
+ elif schema_type in ("integer", "number"):
349
+ schema_kwargs = {
350
+ "type": schema_type.upper(),
351
+ "description": description,
352
+ "default": default,
353
+ "title": title,
354
+ }
355
+ if "maximum" in schema_dict:
356
+ schema_kwargs["maximum"] = schema_dict["maximum"]
357
+ if "minimum" in schema_dict:
358
+ schema_kwargs["minimum"] = schema_dict["minimum"]
359
+ return Schema(**schema_kwargs)
360
+
361
+ elif schema_type == "" and "anyOf" in schema_dict:
362
+ any_of = []
363
+ for sub_schema in schema_dict["anyOf"]:
364
+ sub_schema_converted = convert_schema(sub_schema, root_schema, visited_refs)
365
+ any_of.append(sub_schema_converted)
366
+
367
+ is_nullable = False
368
+ filtered_any_of = []
369
+
370
+ for schema in any_of:
371
+ if schema is None:
372
+ is_nullable = True
373
+ else:
374
+ filtered_any_of.append(schema)
375
+
376
+ any_of = filtered_any_of # type: ignore
377
+ if len(any_of) == 1 and any_of[0] is not None:
378
+ any_of[0].nullable = is_nullable
379
+ return any_of[0]
380
+ else:
381
+ return Schema(
382
+ any_of=any_of,
383
+ description=description,
384
+ default=default,
385
+ title=title,
386
+ )
387
+ else:
388
+ if isinstance(schema_type, list):
389
+ non_null_types = [t for t in schema_type if t != "null"]
390
+ if non_null_types:
391
+ schema_type = non_null_types[0]
392
+ else:
393
+ schema_type = ""
394
+ # Only convert to uppercase if schema_type is not empty
395
+ if schema_type:
396
+ schema_type = schema_type.upper()
397
+ return Schema(type=schema_type, description=description, default=default, title=title)
398
+ else:
399
+ # If we get here with an empty type and no other handlers matched,
400
+ # something is wrong with the schema
401
+ return None
402
+
403
+
404
+ def format_function_definitions(tools_list: List[Dict[str, Any]]) -> Optional[Tool]:
405
+ function_declarations = []
406
+
407
+ for tool in tools_list:
408
+ if tool.get("type") == "function":
409
+ func_info = tool.get("function", {})
410
+ name = func_info.get("name")
411
+ description = func_info.get("description", "")
412
+ parameters_dict = func_info.get("parameters", {})
413
+
414
+ parameters_schema = convert_schema(parameters_dict)
415
+ # Create a FunctionDeclaration instance
416
+ function_decl = FunctionDeclaration(
417
+ name=name,
418
+ description=description,
419
+ parameters=parameters_schema,
420
+ )
421
+
422
+ function_declarations.append(function_decl)
423
+ if function_declarations:
424
+ return Tool(function_declarations=function_declarations)
425
+ else:
426
+ return None
agno/utils/hooks.py ADDED
@@ -0,0 +1,57 @@
1
+ from typing import Any, Callable, Dict, List, Optional, Union
2
+
3
+ from agno.guardrails.base import BaseGuardrail
4
+ from agno.utils.log import log_warning
5
+
6
+
7
+ def normalize_hooks(
8
+ hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]],
9
+ async_mode: bool = False,
10
+ ) -> Optional[List[Callable[..., Any]]]:
11
+ """Normalize hooks to a list format"""
12
+ result_hooks: List[Callable[..., Any]] = []
13
+
14
+ if hooks is not None:
15
+ for hook in hooks:
16
+ if isinstance(hook, BaseGuardrail):
17
+ if async_mode:
18
+ result_hooks.append(hook.async_check)
19
+ else:
20
+ result_hooks.append(hook.check)
21
+ else:
22
+ # Check if the hook is async and used within sync methods
23
+ if not async_mode:
24
+ import asyncio
25
+
26
+ if asyncio.iscoroutinefunction(hook):
27
+ raise ValueError(
28
+ f"Cannot use {hook.__name__} (an async hook) with `run()`. Use `arun()` instead."
29
+ )
30
+
31
+ result_hooks.append(hook)
32
+ return result_hooks if result_hooks else None
33
+
34
+
35
+ def filter_hook_args(hook: Callable[..., Any], all_args: Dict[str, Any]) -> Dict[str, Any]:
36
+ """Filter arguments to only include those that the hook function accepts."""
37
+ import inspect
38
+
39
+ try:
40
+ sig = inspect.signature(hook)
41
+ accepted_params = set(sig.parameters.keys())
42
+
43
+ has_var_keyword = any(param.kind == inspect.Parameter.VAR_KEYWORD for param in sig.parameters.values())
44
+
45
+ # If the function has **kwargs, pass all arguments
46
+ if has_var_keyword:
47
+ return all_args
48
+
49
+ # Otherwise, filter to only include accepted parameters
50
+ filtered_args = {key: value for key, value in all_args.items() if key in accepted_params}
51
+
52
+ return filtered_args
53
+
54
+ except Exception as e:
55
+ log_warning(f"Could not inspect hook signature, passing all arguments: {e}")
56
+ # If signature inspection fails, pass all arguments as fallback
57
+ return all_args