agno 0.1.2__py3-none-any.whl → 2.3.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (723) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +44 -5
  3. agno/agent/agent.py +10531 -2975
  4. agno/api/agent.py +14 -53
  5. agno/api/api.py +7 -46
  6. agno/api/evals.py +22 -0
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -25
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +6 -9
  11. agno/api/schemas/evals.py +16 -0
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +10 -10
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +16 -0
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +22 -26
  18. agno/api/workflow.py +28 -0
  19. agno/cloud/aws/base.py +214 -0
  20. agno/cloud/aws/s3/__init__.py +2 -0
  21. agno/cloud/aws/s3/api_client.py +43 -0
  22. agno/cloud/aws/s3/bucket.py +195 -0
  23. agno/cloud/aws/s3/object.py +57 -0
  24. agno/compression/__init__.py +3 -0
  25. agno/compression/manager.py +247 -0
  26. agno/culture/__init__.py +3 -0
  27. agno/culture/manager.py +956 -0
  28. agno/db/__init__.py +24 -0
  29. agno/db/async_postgres/__init__.py +3 -0
  30. agno/db/base.py +946 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2781 -0
  33. agno/db/dynamo/schemas.py +442 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +2379 -0
  37. agno/db/firestore/schemas.py +181 -0
  38. agno/db/firestore/utils.py +376 -0
  39. agno/db/gcs_json/__init__.py +3 -0
  40. agno/db/gcs_json/gcs_json_db.py +1791 -0
  41. agno/db/gcs_json/utils.py +228 -0
  42. agno/db/in_memory/__init__.py +3 -0
  43. agno/db/in_memory/in_memory_db.py +1312 -0
  44. agno/db/in_memory/utils.py +230 -0
  45. agno/db/json/__init__.py +3 -0
  46. agno/db/json/json_db.py +1777 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/manager.py +199 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/migrations/versions/v2_3_0.py +938 -0
  51. agno/db/mongo/__init__.py +17 -0
  52. agno/db/mongo/async_mongo.py +2760 -0
  53. agno/db/mongo/mongo.py +2597 -0
  54. agno/db/mongo/schemas.py +119 -0
  55. agno/db/mongo/utils.py +276 -0
  56. agno/db/mysql/__init__.py +4 -0
  57. agno/db/mysql/async_mysql.py +2912 -0
  58. agno/db/mysql/mysql.py +2923 -0
  59. agno/db/mysql/schemas.py +186 -0
  60. agno/db/mysql/utils.py +488 -0
  61. agno/db/postgres/__init__.py +4 -0
  62. agno/db/postgres/async_postgres.py +2579 -0
  63. agno/db/postgres/postgres.py +2870 -0
  64. agno/db/postgres/schemas.py +187 -0
  65. agno/db/postgres/utils.py +442 -0
  66. agno/db/redis/__init__.py +3 -0
  67. agno/db/redis/redis.py +2141 -0
  68. agno/db/redis/schemas.py +159 -0
  69. agno/db/redis/utils.py +346 -0
  70. agno/db/schemas/__init__.py +4 -0
  71. agno/db/schemas/culture.py +120 -0
  72. agno/db/schemas/evals.py +34 -0
  73. agno/db/schemas/knowledge.py +40 -0
  74. agno/db/schemas/memory.py +61 -0
  75. agno/db/singlestore/__init__.py +3 -0
  76. agno/db/singlestore/schemas.py +179 -0
  77. agno/db/singlestore/singlestore.py +2877 -0
  78. agno/db/singlestore/utils.py +384 -0
  79. agno/db/sqlite/__init__.py +4 -0
  80. agno/db/sqlite/async_sqlite.py +2911 -0
  81. agno/db/sqlite/schemas.py +181 -0
  82. agno/db/sqlite/sqlite.py +2908 -0
  83. agno/db/sqlite/utils.py +429 -0
  84. agno/db/surrealdb/__init__.py +3 -0
  85. agno/db/surrealdb/metrics.py +292 -0
  86. agno/db/surrealdb/models.py +334 -0
  87. agno/db/surrealdb/queries.py +71 -0
  88. agno/db/surrealdb/surrealdb.py +1908 -0
  89. agno/db/surrealdb/utils.py +147 -0
  90. agno/db/utils.py +118 -0
  91. agno/eval/__init__.py +24 -0
  92. agno/eval/accuracy.py +666 -276
  93. agno/eval/agent_as_judge.py +861 -0
  94. agno/eval/base.py +29 -0
  95. agno/eval/performance.py +779 -0
  96. agno/eval/reliability.py +241 -62
  97. agno/eval/utils.py +120 -0
  98. agno/exceptions.py +143 -1
  99. agno/filters.py +354 -0
  100. agno/guardrails/__init__.py +6 -0
  101. agno/guardrails/base.py +19 -0
  102. agno/guardrails/openai.py +144 -0
  103. agno/guardrails/pii.py +94 -0
  104. agno/guardrails/prompt_injection.py +52 -0
  105. agno/hooks/__init__.py +3 -0
  106. agno/hooks/decorator.py +164 -0
  107. agno/integrations/discord/__init__.py +3 -0
  108. agno/integrations/discord/client.py +203 -0
  109. agno/knowledge/__init__.py +5 -1
  110. agno/{document → knowledge}/chunking/agentic.py +22 -14
  111. agno/{document → knowledge}/chunking/document.py +2 -2
  112. agno/{document → knowledge}/chunking/fixed.py +7 -6
  113. agno/knowledge/chunking/markdown.py +151 -0
  114. agno/{document → knowledge}/chunking/recursive.py +15 -3
  115. agno/knowledge/chunking/row.py +39 -0
  116. agno/knowledge/chunking/semantic.py +91 -0
  117. agno/knowledge/chunking/strategy.py +165 -0
  118. agno/knowledge/content.py +74 -0
  119. agno/knowledge/document/__init__.py +5 -0
  120. agno/{document → knowledge/document}/base.py +12 -2
  121. agno/knowledge/embedder/__init__.py +5 -0
  122. agno/knowledge/embedder/aws_bedrock.py +343 -0
  123. agno/knowledge/embedder/azure_openai.py +210 -0
  124. agno/{embedder → knowledge/embedder}/base.py +8 -0
  125. agno/knowledge/embedder/cohere.py +323 -0
  126. agno/knowledge/embedder/fastembed.py +62 -0
  127. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  128. agno/knowledge/embedder/google.py +258 -0
  129. agno/knowledge/embedder/huggingface.py +94 -0
  130. agno/knowledge/embedder/jina.py +182 -0
  131. agno/knowledge/embedder/langdb.py +22 -0
  132. agno/knowledge/embedder/mistral.py +206 -0
  133. agno/knowledge/embedder/nebius.py +13 -0
  134. agno/knowledge/embedder/ollama.py +154 -0
  135. agno/knowledge/embedder/openai.py +195 -0
  136. agno/knowledge/embedder/sentence_transformer.py +63 -0
  137. agno/{embedder → knowledge/embedder}/together.py +1 -1
  138. agno/knowledge/embedder/vllm.py +262 -0
  139. agno/knowledge/embedder/voyageai.py +165 -0
  140. agno/knowledge/knowledge.py +3006 -0
  141. agno/knowledge/reader/__init__.py +7 -0
  142. agno/knowledge/reader/arxiv_reader.py +81 -0
  143. agno/knowledge/reader/base.py +95 -0
  144. agno/knowledge/reader/csv_reader.py +164 -0
  145. agno/knowledge/reader/docx_reader.py +82 -0
  146. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  147. agno/knowledge/reader/firecrawl_reader.py +201 -0
  148. agno/knowledge/reader/json_reader.py +88 -0
  149. agno/knowledge/reader/markdown_reader.py +137 -0
  150. agno/knowledge/reader/pdf_reader.py +431 -0
  151. agno/knowledge/reader/pptx_reader.py +101 -0
  152. agno/knowledge/reader/reader_factory.py +313 -0
  153. agno/knowledge/reader/s3_reader.py +89 -0
  154. agno/knowledge/reader/tavily_reader.py +193 -0
  155. agno/knowledge/reader/text_reader.py +127 -0
  156. agno/knowledge/reader/web_search_reader.py +325 -0
  157. agno/knowledge/reader/website_reader.py +455 -0
  158. agno/knowledge/reader/wikipedia_reader.py +91 -0
  159. agno/knowledge/reader/youtube_reader.py +78 -0
  160. agno/knowledge/remote_content/remote_content.py +88 -0
  161. agno/knowledge/reranker/__init__.py +3 -0
  162. agno/{reranker → knowledge/reranker}/base.py +1 -1
  163. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  164. agno/knowledge/reranker/infinity.py +195 -0
  165. agno/knowledge/reranker/sentence_transformer.py +54 -0
  166. agno/knowledge/types.py +39 -0
  167. agno/knowledge/utils.py +234 -0
  168. agno/media.py +439 -95
  169. agno/memory/__init__.py +16 -3
  170. agno/memory/manager.py +1474 -123
  171. agno/memory/strategies/__init__.py +15 -0
  172. agno/memory/strategies/base.py +66 -0
  173. agno/memory/strategies/summarize.py +196 -0
  174. agno/memory/strategies/types.py +37 -0
  175. agno/models/aimlapi/__init__.py +5 -0
  176. agno/models/aimlapi/aimlapi.py +62 -0
  177. agno/models/anthropic/__init__.py +4 -0
  178. agno/models/anthropic/claude.py +960 -496
  179. agno/models/aws/__init__.py +15 -0
  180. agno/models/aws/bedrock.py +686 -451
  181. agno/models/aws/claude.py +190 -183
  182. agno/models/azure/__init__.py +18 -1
  183. agno/models/azure/ai_foundry.py +489 -0
  184. agno/models/azure/openai_chat.py +89 -40
  185. agno/models/base.py +2477 -550
  186. agno/models/cerebras/__init__.py +12 -0
  187. agno/models/cerebras/cerebras.py +565 -0
  188. agno/models/cerebras/cerebras_openai.py +131 -0
  189. agno/models/cohere/__init__.py +4 -0
  190. agno/models/cohere/chat.py +306 -492
  191. agno/models/cometapi/__init__.py +5 -0
  192. agno/models/cometapi/cometapi.py +74 -0
  193. agno/models/dashscope/__init__.py +5 -0
  194. agno/models/dashscope/dashscope.py +90 -0
  195. agno/models/deepinfra/__init__.py +5 -0
  196. agno/models/deepinfra/deepinfra.py +45 -0
  197. agno/models/deepseek/__init__.py +4 -0
  198. agno/models/deepseek/deepseek.py +110 -9
  199. agno/models/fireworks/__init__.py +4 -0
  200. agno/models/fireworks/fireworks.py +19 -22
  201. agno/models/google/__init__.py +3 -7
  202. agno/models/google/gemini.py +1717 -662
  203. agno/models/google/utils.py +22 -0
  204. agno/models/groq/__init__.py +4 -0
  205. agno/models/groq/groq.py +391 -666
  206. agno/models/huggingface/__init__.py +4 -0
  207. agno/models/huggingface/huggingface.py +266 -538
  208. agno/models/ibm/__init__.py +5 -0
  209. agno/models/ibm/watsonx.py +432 -0
  210. agno/models/internlm/__init__.py +3 -0
  211. agno/models/internlm/internlm.py +20 -3
  212. agno/models/langdb/__init__.py +1 -0
  213. agno/models/langdb/langdb.py +60 -0
  214. agno/models/litellm/__init__.py +14 -0
  215. agno/models/litellm/chat.py +503 -0
  216. agno/models/litellm/litellm_openai.py +42 -0
  217. agno/models/llama_cpp/__init__.py +5 -0
  218. agno/models/llama_cpp/llama_cpp.py +22 -0
  219. agno/models/lmstudio/__init__.py +5 -0
  220. agno/models/lmstudio/lmstudio.py +25 -0
  221. agno/models/message.py +361 -39
  222. agno/models/meta/__init__.py +12 -0
  223. agno/models/meta/llama.py +502 -0
  224. agno/models/meta/llama_openai.py +79 -0
  225. agno/models/metrics.py +120 -0
  226. agno/models/mistral/__init__.py +4 -0
  227. agno/models/mistral/mistral.py +293 -393
  228. agno/models/nebius/__init__.py +3 -0
  229. agno/models/nebius/nebius.py +53 -0
  230. agno/models/nexus/__init__.py +3 -0
  231. agno/models/nexus/nexus.py +22 -0
  232. agno/models/nvidia/__init__.py +4 -0
  233. agno/models/nvidia/nvidia.py +22 -3
  234. agno/models/ollama/__init__.py +4 -2
  235. agno/models/ollama/chat.py +257 -492
  236. agno/models/openai/__init__.py +7 -0
  237. agno/models/openai/chat.py +725 -770
  238. agno/models/openai/like.py +16 -2
  239. agno/models/openai/responses.py +1121 -0
  240. agno/models/openrouter/__init__.py +4 -0
  241. agno/models/openrouter/openrouter.py +62 -5
  242. agno/models/perplexity/__init__.py +5 -0
  243. agno/models/perplexity/perplexity.py +203 -0
  244. agno/models/portkey/__init__.py +3 -0
  245. agno/models/portkey/portkey.py +82 -0
  246. agno/models/requesty/__init__.py +5 -0
  247. agno/models/requesty/requesty.py +69 -0
  248. agno/models/response.py +177 -7
  249. agno/models/sambanova/__init__.py +4 -0
  250. agno/models/sambanova/sambanova.py +23 -4
  251. agno/models/siliconflow/__init__.py +5 -0
  252. agno/models/siliconflow/siliconflow.py +42 -0
  253. agno/models/together/__init__.py +4 -0
  254. agno/models/together/together.py +21 -164
  255. agno/models/utils.py +266 -0
  256. agno/models/vercel/__init__.py +3 -0
  257. agno/models/vercel/v0.py +43 -0
  258. agno/models/vertexai/__init__.py +0 -1
  259. agno/models/vertexai/claude.py +190 -0
  260. agno/models/vllm/__init__.py +3 -0
  261. agno/models/vllm/vllm.py +83 -0
  262. agno/models/xai/__init__.py +2 -0
  263. agno/models/xai/xai.py +111 -7
  264. agno/os/__init__.py +3 -0
  265. agno/os/app.py +1027 -0
  266. agno/os/auth.py +244 -0
  267. agno/os/config.py +126 -0
  268. agno/os/interfaces/__init__.py +1 -0
  269. agno/os/interfaces/a2a/__init__.py +3 -0
  270. agno/os/interfaces/a2a/a2a.py +42 -0
  271. agno/os/interfaces/a2a/router.py +249 -0
  272. agno/os/interfaces/a2a/utils.py +924 -0
  273. agno/os/interfaces/agui/__init__.py +3 -0
  274. agno/os/interfaces/agui/agui.py +47 -0
  275. agno/os/interfaces/agui/router.py +147 -0
  276. agno/os/interfaces/agui/utils.py +574 -0
  277. agno/os/interfaces/base.py +25 -0
  278. agno/os/interfaces/slack/__init__.py +3 -0
  279. agno/os/interfaces/slack/router.py +148 -0
  280. agno/os/interfaces/slack/security.py +30 -0
  281. agno/os/interfaces/slack/slack.py +47 -0
  282. agno/os/interfaces/whatsapp/__init__.py +3 -0
  283. agno/os/interfaces/whatsapp/router.py +210 -0
  284. agno/os/interfaces/whatsapp/security.py +55 -0
  285. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  286. agno/os/mcp.py +293 -0
  287. agno/os/middleware/__init__.py +9 -0
  288. agno/os/middleware/jwt.py +797 -0
  289. agno/os/router.py +258 -0
  290. agno/os/routers/__init__.py +3 -0
  291. agno/os/routers/agents/__init__.py +3 -0
  292. agno/os/routers/agents/router.py +599 -0
  293. agno/os/routers/agents/schema.py +261 -0
  294. agno/os/routers/evals/__init__.py +3 -0
  295. agno/os/routers/evals/evals.py +450 -0
  296. agno/os/routers/evals/schemas.py +174 -0
  297. agno/os/routers/evals/utils.py +231 -0
  298. agno/os/routers/health.py +31 -0
  299. agno/os/routers/home.py +52 -0
  300. agno/os/routers/knowledge/__init__.py +3 -0
  301. agno/os/routers/knowledge/knowledge.py +1008 -0
  302. agno/os/routers/knowledge/schemas.py +178 -0
  303. agno/os/routers/memory/__init__.py +3 -0
  304. agno/os/routers/memory/memory.py +661 -0
  305. agno/os/routers/memory/schemas.py +88 -0
  306. agno/os/routers/metrics/__init__.py +3 -0
  307. agno/os/routers/metrics/metrics.py +190 -0
  308. agno/os/routers/metrics/schemas.py +47 -0
  309. agno/os/routers/session/__init__.py +3 -0
  310. agno/os/routers/session/session.py +997 -0
  311. agno/os/routers/teams/__init__.py +3 -0
  312. agno/os/routers/teams/router.py +512 -0
  313. agno/os/routers/teams/schema.py +257 -0
  314. agno/os/routers/traces/__init__.py +3 -0
  315. agno/os/routers/traces/schemas.py +414 -0
  316. agno/os/routers/traces/traces.py +499 -0
  317. agno/os/routers/workflows/__init__.py +3 -0
  318. agno/os/routers/workflows/router.py +624 -0
  319. agno/os/routers/workflows/schema.py +75 -0
  320. agno/os/schema.py +534 -0
  321. agno/os/scopes.py +469 -0
  322. agno/{playground → os}/settings.py +7 -15
  323. agno/os/utils.py +973 -0
  324. agno/reasoning/anthropic.py +80 -0
  325. agno/reasoning/azure_ai_foundry.py +67 -0
  326. agno/reasoning/deepseek.py +63 -0
  327. agno/reasoning/default.py +97 -0
  328. agno/reasoning/gemini.py +73 -0
  329. agno/reasoning/groq.py +71 -0
  330. agno/reasoning/helpers.py +24 -1
  331. agno/reasoning/ollama.py +67 -0
  332. agno/reasoning/openai.py +86 -0
  333. agno/reasoning/step.py +2 -1
  334. agno/reasoning/vertexai.py +76 -0
  335. agno/run/__init__.py +6 -0
  336. agno/run/agent.py +822 -0
  337. agno/run/base.py +247 -0
  338. agno/run/cancel.py +81 -0
  339. agno/run/requirement.py +181 -0
  340. agno/run/team.py +767 -0
  341. agno/run/workflow.py +708 -0
  342. agno/session/__init__.py +10 -0
  343. agno/session/agent.py +260 -0
  344. agno/session/summary.py +265 -0
  345. agno/session/team.py +342 -0
  346. agno/session/workflow.py +501 -0
  347. agno/table.py +10 -0
  348. agno/team/__init__.py +37 -0
  349. agno/team/team.py +9536 -0
  350. agno/tools/__init__.py +7 -0
  351. agno/tools/agentql.py +120 -0
  352. agno/tools/airflow.py +22 -12
  353. agno/tools/api.py +122 -0
  354. agno/tools/apify.py +276 -83
  355. agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
  356. agno/tools/aws_lambda.py +28 -7
  357. agno/tools/aws_ses.py +66 -0
  358. agno/tools/baidusearch.py +11 -4
  359. agno/tools/bitbucket.py +292 -0
  360. agno/tools/brandfetch.py +213 -0
  361. agno/tools/bravesearch.py +106 -0
  362. agno/tools/brightdata.py +367 -0
  363. agno/tools/browserbase.py +209 -0
  364. agno/tools/calcom.py +32 -23
  365. agno/tools/calculator.py +24 -37
  366. agno/tools/cartesia.py +187 -0
  367. agno/tools/{clickup_tool.py → clickup.py} +17 -28
  368. agno/tools/confluence.py +91 -26
  369. agno/tools/crawl4ai.py +139 -43
  370. agno/tools/csv_toolkit.py +28 -22
  371. agno/tools/dalle.py +36 -22
  372. agno/tools/daytona.py +475 -0
  373. agno/tools/decorator.py +169 -14
  374. agno/tools/desi_vocal.py +23 -11
  375. agno/tools/discord.py +32 -29
  376. agno/tools/docker.py +716 -0
  377. agno/tools/duckdb.py +76 -81
  378. agno/tools/duckduckgo.py +43 -40
  379. agno/tools/e2b.py +703 -0
  380. agno/tools/eleven_labs.py +65 -54
  381. agno/tools/email.py +13 -5
  382. agno/tools/evm.py +129 -0
  383. agno/tools/exa.py +324 -42
  384. agno/tools/fal.py +39 -35
  385. agno/tools/file.py +196 -30
  386. agno/tools/file_generation.py +356 -0
  387. agno/tools/financial_datasets.py +288 -0
  388. agno/tools/firecrawl.py +108 -33
  389. agno/tools/function.py +960 -122
  390. agno/tools/giphy.py +34 -12
  391. agno/tools/github.py +1294 -97
  392. agno/tools/gmail.py +922 -0
  393. agno/tools/google_bigquery.py +117 -0
  394. agno/tools/google_drive.py +271 -0
  395. agno/tools/google_maps.py +253 -0
  396. agno/tools/googlecalendar.py +607 -107
  397. agno/tools/googlesheets.py +377 -0
  398. agno/tools/hackernews.py +20 -12
  399. agno/tools/jina.py +24 -14
  400. agno/tools/jira.py +48 -19
  401. agno/tools/knowledge.py +218 -0
  402. agno/tools/linear.py +82 -43
  403. agno/tools/linkup.py +58 -0
  404. agno/tools/local_file_system.py +15 -7
  405. agno/tools/lumalab.py +41 -26
  406. agno/tools/mcp/__init__.py +10 -0
  407. agno/tools/mcp/mcp.py +331 -0
  408. agno/tools/mcp/multi_mcp.py +347 -0
  409. agno/tools/mcp/params.py +24 -0
  410. agno/tools/mcp_toolbox.py +284 -0
  411. agno/tools/mem0.py +193 -0
  412. agno/tools/memory.py +419 -0
  413. agno/tools/mlx_transcribe.py +11 -9
  414. agno/tools/models/azure_openai.py +190 -0
  415. agno/tools/models/gemini.py +203 -0
  416. agno/tools/models/groq.py +158 -0
  417. agno/tools/models/morph.py +186 -0
  418. agno/tools/models/nebius.py +124 -0
  419. agno/tools/models_labs.py +163 -82
  420. agno/tools/moviepy_video.py +18 -13
  421. agno/tools/nano_banana.py +151 -0
  422. agno/tools/neo4j.py +134 -0
  423. agno/tools/newspaper.py +15 -4
  424. agno/tools/newspaper4k.py +19 -6
  425. agno/tools/notion.py +204 -0
  426. agno/tools/openai.py +181 -17
  427. agno/tools/openbb.py +27 -20
  428. agno/tools/opencv.py +321 -0
  429. agno/tools/openweather.py +233 -0
  430. agno/tools/oxylabs.py +385 -0
  431. agno/tools/pandas.py +25 -15
  432. agno/tools/parallel.py +314 -0
  433. agno/tools/postgres.py +238 -185
  434. agno/tools/pubmed.py +125 -13
  435. agno/tools/python.py +48 -35
  436. agno/tools/reasoning.py +283 -0
  437. agno/tools/reddit.py +207 -29
  438. agno/tools/redshift.py +406 -0
  439. agno/tools/replicate.py +69 -26
  440. agno/tools/resend.py +11 -6
  441. agno/tools/scrapegraph.py +179 -19
  442. agno/tools/searxng.py +23 -31
  443. agno/tools/serpapi.py +15 -10
  444. agno/tools/serper.py +255 -0
  445. agno/tools/shell.py +23 -12
  446. agno/tools/shopify.py +1519 -0
  447. agno/tools/slack.py +56 -14
  448. agno/tools/sleep.py +8 -6
  449. agno/tools/spider.py +35 -11
  450. agno/tools/spotify.py +919 -0
  451. agno/tools/sql.py +34 -19
  452. agno/tools/tavily.py +158 -8
  453. agno/tools/telegram.py +18 -8
  454. agno/tools/todoist.py +218 -0
  455. agno/tools/toolkit.py +134 -9
  456. agno/tools/trafilatura.py +388 -0
  457. agno/tools/trello.py +25 -28
  458. agno/tools/twilio.py +18 -9
  459. agno/tools/user_control_flow.py +78 -0
  460. agno/tools/valyu.py +228 -0
  461. agno/tools/visualization.py +467 -0
  462. agno/tools/webbrowser.py +28 -0
  463. agno/tools/webex.py +76 -0
  464. agno/tools/website.py +23 -19
  465. agno/tools/webtools.py +45 -0
  466. agno/tools/whatsapp.py +286 -0
  467. agno/tools/wikipedia.py +28 -19
  468. agno/tools/workflow.py +285 -0
  469. agno/tools/{twitter.py → x.py} +142 -46
  470. agno/tools/yfinance.py +41 -39
  471. agno/tools/youtube.py +34 -17
  472. agno/tools/zendesk.py +15 -5
  473. agno/tools/zep.py +454 -0
  474. agno/tools/zoom.py +86 -37
  475. agno/tracing/__init__.py +12 -0
  476. agno/tracing/exporter.py +157 -0
  477. agno/tracing/schemas.py +276 -0
  478. agno/tracing/setup.py +111 -0
  479. agno/utils/agent.py +938 -0
  480. agno/utils/audio.py +37 -1
  481. agno/utils/certs.py +27 -0
  482. agno/utils/code_execution.py +11 -0
  483. agno/utils/common.py +103 -20
  484. agno/utils/cryptography.py +22 -0
  485. agno/utils/dttm.py +33 -0
  486. agno/utils/events.py +700 -0
  487. agno/utils/functions.py +107 -37
  488. agno/utils/gemini.py +426 -0
  489. agno/utils/hooks.py +171 -0
  490. agno/utils/http.py +185 -0
  491. agno/utils/json_schema.py +159 -37
  492. agno/utils/knowledge.py +36 -0
  493. agno/utils/location.py +19 -0
  494. agno/utils/log.py +221 -8
  495. agno/utils/mcp.py +214 -0
  496. agno/utils/media.py +335 -14
  497. agno/utils/merge_dict.py +22 -1
  498. agno/utils/message.py +77 -2
  499. agno/utils/models/ai_foundry.py +50 -0
  500. agno/utils/models/claude.py +373 -0
  501. agno/utils/models/cohere.py +94 -0
  502. agno/utils/models/llama.py +85 -0
  503. agno/utils/models/mistral.py +100 -0
  504. agno/utils/models/openai_responses.py +140 -0
  505. agno/utils/models/schema_utils.py +153 -0
  506. agno/utils/models/watsonx.py +41 -0
  507. agno/utils/openai.py +257 -0
  508. agno/utils/pickle.py +1 -1
  509. agno/utils/pprint.py +124 -8
  510. agno/utils/print_response/agent.py +930 -0
  511. agno/utils/print_response/team.py +1914 -0
  512. agno/utils/print_response/workflow.py +1668 -0
  513. agno/utils/prompts.py +111 -0
  514. agno/utils/reasoning.py +108 -0
  515. agno/utils/response.py +163 -0
  516. agno/utils/serialize.py +32 -0
  517. agno/utils/shell.py +4 -4
  518. agno/utils/streamlit.py +487 -0
  519. agno/utils/string.py +204 -51
  520. agno/utils/team.py +139 -0
  521. agno/utils/timer.py +9 -2
  522. agno/utils/tokens.py +657 -0
  523. agno/utils/tools.py +19 -1
  524. agno/utils/whatsapp.py +305 -0
  525. agno/utils/yaml_io.py +3 -3
  526. agno/vectordb/__init__.py +2 -0
  527. agno/vectordb/base.py +87 -9
  528. agno/vectordb/cassandra/__init__.py +5 -1
  529. agno/vectordb/cassandra/cassandra.py +383 -27
  530. agno/vectordb/chroma/__init__.py +4 -0
  531. agno/vectordb/chroma/chromadb.py +748 -83
  532. agno/vectordb/clickhouse/__init__.py +7 -1
  533. agno/vectordb/clickhouse/clickhousedb.py +554 -53
  534. agno/vectordb/couchbase/__init__.py +3 -0
  535. agno/vectordb/couchbase/couchbase.py +1446 -0
  536. agno/vectordb/lancedb/__init__.py +5 -0
  537. agno/vectordb/lancedb/lance_db.py +730 -98
  538. agno/vectordb/langchaindb/__init__.py +5 -0
  539. agno/vectordb/langchaindb/langchaindb.py +163 -0
  540. agno/vectordb/lightrag/__init__.py +5 -0
  541. agno/vectordb/lightrag/lightrag.py +388 -0
  542. agno/vectordb/llamaindex/__init__.py +3 -0
  543. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  544. agno/vectordb/milvus/__init__.py +3 -0
  545. agno/vectordb/milvus/milvus.py +966 -78
  546. agno/vectordb/mongodb/__init__.py +9 -1
  547. agno/vectordb/mongodb/mongodb.py +1175 -172
  548. agno/vectordb/pgvector/__init__.py +8 -0
  549. agno/vectordb/pgvector/pgvector.py +599 -115
  550. agno/vectordb/pineconedb/__init__.py +5 -1
  551. agno/vectordb/pineconedb/pineconedb.py +406 -43
  552. agno/vectordb/qdrant/__init__.py +4 -0
  553. agno/vectordb/qdrant/qdrant.py +914 -61
  554. agno/vectordb/redis/__init__.py +9 -0
  555. agno/vectordb/redis/redisdb.py +682 -0
  556. agno/vectordb/singlestore/__init__.py +8 -1
  557. agno/vectordb/singlestore/singlestore.py +771 -0
  558. agno/vectordb/surrealdb/__init__.py +3 -0
  559. agno/vectordb/surrealdb/surrealdb.py +663 -0
  560. agno/vectordb/upstashdb/__init__.py +5 -0
  561. agno/vectordb/upstashdb/upstashdb.py +718 -0
  562. agno/vectordb/weaviate/__init__.py +8 -0
  563. agno/vectordb/weaviate/index.py +15 -0
  564. agno/vectordb/weaviate/weaviate.py +1009 -0
  565. agno/workflow/__init__.py +23 -1
  566. agno/workflow/agent.py +299 -0
  567. agno/workflow/condition.py +759 -0
  568. agno/workflow/loop.py +756 -0
  569. agno/workflow/parallel.py +853 -0
  570. agno/workflow/router.py +723 -0
  571. agno/workflow/step.py +1564 -0
  572. agno/workflow/steps.py +613 -0
  573. agno/workflow/types.py +556 -0
  574. agno/workflow/workflow.py +4327 -514
  575. agno-2.3.13.dist-info/METADATA +639 -0
  576. agno-2.3.13.dist-info/RECORD +613 -0
  577. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
  578. agno-2.3.13.dist-info/licenses/LICENSE +201 -0
  579. agno/api/playground.py +0 -91
  580. agno/api/schemas/playground.py +0 -22
  581. agno/api/schemas/user.py +0 -22
  582. agno/api/schemas/workspace.py +0 -46
  583. agno/api/user.py +0 -160
  584. agno/api/workspace.py +0 -151
  585. agno/cli/auth_server.py +0 -118
  586. agno/cli/config.py +0 -275
  587. agno/cli/console.py +0 -88
  588. agno/cli/credentials.py +0 -23
  589. agno/cli/entrypoint.py +0 -571
  590. agno/cli/operator.py +0 -355
  591. agno/cli/settings.py +0 -85
  592. agno/cli/ws/ws_cli.py +0 -817
  593. agno/constants.py +0 -13
  594. agno/document/__init__.py +0 -1
  595. agno/document/chunking/semantic.py +0 -47
  596. agno/document/chunking/strategy.py +0 -31
  597. agno/document/reader/__init__.py +0 -1
  598. agno/document/reader/arxiv_reader.py +0 -41
  599. agno/document/reader/base.py +0 -22
  600. agno/document/reader/csv_reader.py +0 -84
  601. agno/document/reader/docx_reader.py +0 -46
  602. agno/document/reader/firecrawl_reader.py +0 -99
  603. agno/document/reader/json_reader.py +0 -43
  604. agno/document/reader/pdf_reader.py +0 -219
  605. agno/document/reader/s3/pdf_reader.py +0 -46
  606. agno/document/reader/s3/text_reader.py +0 -51
  607. agno/document/reader/text_reader.py +0 -41
  608. agno/document/reader/website_reader.py +0 -175
  609. agno/document/reader/youtube_reader.py +0 -50
  610. agno/embedder/__init__.py +0 -1
  611. agno/embedder/azure_openai.py +0 -86
  612. agno/embedder/cohere.py +0 -72
  613. agno/embedder/fastembed.py +0 -37
  614. agno/embedder/google.py +0 -73
  615. agno/embedder/huggingface.py +0 -54
  616. agno/embedder/mistral.py +0 -80
  617. agno/embedder/ollama.py +0 -57
  618. agno/embedder/openai.py +0 -74
  619. agno/embedder/sentence_transformer.py +0 -38
  620. agno/embedder/voyageai.py +0 -64
  621. agno/eval/perf.py +0 -201
  622. agno/file/__init__.py +0 -1
  623. agno/file/file.py +0 -16
  624. agno/file/local/csv.py +0 -32
  625. agno/file/local/txt.py +0 -19
  626. agno/infra/app.py +0 -240
  627. agno/infra/base.py +0 -144
  628. agno/infra/context.py +0 -20
  629. agno/infra/db_app.py +0 -52
  630. agno/infra/resource.py +0 -205
  631. agno/infra/resources.py +0 -55
  632. agno/knowledge/agent.py +0 -230
  633. agno/knowledge/arxiv.py +0 -22
  634. agno/knowledge/combined.py +0 -22
  635. agno/knowledge/csv.py +0 -28
  636. agno/knowledge/csv_url.py +0 -19
  637. agno/knowledge/document.py +0 -20
  638. agno/knowledge/docx.py +0 -30
  639. agno/knowledge/json.py +0 -28
  640. agno/knowledge/langchain.py +0 -71
  641. agno/knowledge/llamaindex.py +0 -66
  642. agno/knowledge/pdf.py +0 -28
  643. agno/knowledge/pdf_url.py +0 -26
  644. agno/knowledge/s3/base.py +0 -60
  645. agno/knowledge/s3/pdf.py +0 -21
  646. agno/knowledge/s3/text.py +0 -23
  647. agno/knowledge/text.py +0 -30
  648. agno/knowledge/website.py +0 -88
  649. agno/knowledge/wikipedia.py +0 -31
  650. agno/knowledge/youtube.py +0 -22
  651. agno/memory/agent.py +0 -392
  652. agno/memory/classifier.py +0 -104
  653. agno/memory/db/__init__.py +0 -1
  654. agno/memory/db/base.py +0 -42
  655. agno/memory/db/mongodb.py +0 -189
  656. agno/memory/db/postgres.py +0 -203
  657. agno/memory/db/sqlite.py +0 -193
  658. agno/memory/memory.py +0 -15
  659. agno/memory/row.py +0 -36
  660. agno/memory/summarizer.py +0 -192
  661. agno/memory/summary.py +0 -19
  662. agno/memory/workflow.py +0 -38
  663. agno/models/google/gemini_openai.py +0 -26
  664. agno/models/ollama/hermes.py +0 -221
  665. agno/models/ollama/tools.py +0 -362
  666. agno/models/vertexai/gemini.py +0 -595
  667. agno/playground/__init__.py +0 -3
  668. agno/playground/async_router.py +0 -421
  669. agno/playground/deploy.py +0 -249
  670. agno/playground/operator.py +0 -92
  671. agno/playground/playground.py +0 -91
  672. agno/playground/schemas.py +0 -76
  673. agno/playground/serve.py +0 -55
  674. agno/playground/sync_router.py +0 -405
  675. agno/reasoning/agent.py +0 -68
  676. agno/run/response.py +0 -112
  677. agno/storage/agent/__init__.py +0 -0
  678. agno/storage/agent/base.py +0 -38
  679. agno/storage/agent/dynamodb.py +0 -350
  680. agno/storage/agent/json.py +0 -92
  681. agno/storage/agent/mongodb.py +0 -228
  682. agno/storage/agent/postgres.py +0 -367
  683. agno/storage/agent/session.py +0 -79
  684. agno/storage/agent/singlestore.py +0 -303
  685. agno/storage/agent/sqlite.py +0 -357
  686. agno/storage/agent/yaml.py +0 -93
  687. agno/storage/workflow/__init__.py +0 -0
  688. agno/storage/workflow/base.py +0 -40
  689. agno/storage/workflow/mongodb.py +0 -233
  690. agno/storage/workflow/postgres.py +0 -366
  691. agno/storage/workflow/session.py +0 -60
  692. agno/storage/workflow/sqlite.py +0 -359
  693. agno/tools/googlesearch.py +0 -88
  694. agno/utils/defaults.py +0 -57
  695. agno/utils/filesystem.py +0 -39
  696. agno/utils/git.py +0 -52
  697. agno/utils/json_io.py +0 -30
  698. agno/utils/load_env.py +0 -19
  699. agno/utils/py_io.py +0 -19
  700. agno/utils/pyproject.py +0 -18
  701. agno/utils/resource_filter.py +0 -31
  702. agno/vectordb/singlestore/s2vectordb.py +0 -390
  703. agno/vectordb/singlestore/s2vectordb2.py +0 -355
  704. agno/workspace/__init__.py +0 -0
  705. agno/workspace/config.py +0 -325
  706. agno/workspace/enums.py +0 -6
  707. agno/workspace/helpers.py +0 -48
  708. agno/workspace/operator.py +0 -758
  709. agno/workspace/settings.py +0 -63
  710. agno-0.1.2.dist-info/LICENSE +0 -375
  711. agno-0.1.2.dist-info/METADATA +0 -502
  712. agno-0.1.2.dist-info/RECORD +0 -352
  713. agno-0.1.2.dist-info/entry_points.txt +0 -3
  714. /agno/{cli → db/migrations}/__init__.py +0 -0
  715. /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
  716. /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
  717. /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
  718. /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
  719. /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
  720. /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
  721. /agno/{reranker → utils/models}/__init__.py +0 -0
  722. /agno/{storage → utils/print_response}/__init__.py +0 -0
  723. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
agno/utils/functions.py CHANGED
@@ -1,8 +1,10 @@
1
1
  import json
2
- from typing import Any, Dict, Optional
2
+ from typing import Any, Callable, Dict, Optional, TypeVar
3
3
 
4
4
  from agno.tools.function import Function, FunctionCall
5
- from agno.utils.log import logger
5
+ from agno.utils.log import log_debug, log_error
6
+
7
+ T = TypeVar("T")
6
8
 
7
9
 
8
10
  def get_function_call(
@@ -11,7 +13,6 @@ def get_function_call(
11
13
  call_id: Optional[str] = None,
12
14
  functions: Optional[Dict[str, Function]] = None,
13
15
  ) -> Optional[FunctionCall]:
14
- logger.debug(f"Getting function {name}")
15
16
  if functions is None:
16
17
  return None
17
18
 
@@ -19,7 +20,7 @@ def get_function_call(
19
20
  if name in functions:
20
21
  function_to_call = functions[name]
21
22
  if function_to_call is None:
22
- logger.error(f"Function {name} not found")
23
+ log_error(f"Function {name} not found")
23
24
  return None
24
25
 
25
26
  function_call = FunctionCall(function=function_to_call)
@@ -27,16 +28,14 @@ def get_function_call(
27
28
  function_call.call_id = call_id
28
29
  if arguments is not None and arguments != "":
29
30
  try:
30
- if function_to_call.sanitize_arguments:
31
- if "None" in arguments:
32
- arguments = arguments.replace("None", "null")
33
- if "True" in arguments:
34
- arguments = arguments.replace("True", "true")
35
- if "False" in arguments:
36
- arguments = arguments.replace("False", "false")
37
- _arguments = json.loads(arguments)
31
+ try:
32
+ _arguments = json.loads(arguments)
33
+ except Exception:
34
+ import ast
35
+
36
+ _arguments = ast.literal_eval(arguments)
38
37
  except Exception as e:
39
- logger.error(f"Unable to decode function arguments:\n{arguments}\nError: {e}")
38
+ log_error(f"Unable to decode function arguments:\n{arguments}\nError: {e}")
40
39
  function_call.error = (
41
40
  f"Error while decoding function arguments: {e}\n\n"
42
41
  f"Please make sure we can json.loads() the arguments and retry."
@@ -44,7 +43,7 @@ def get_function_call(
44
43
  return function_call
45
44
 
46
45
  if not isinstance(_arguments, dict):
47
- logger.error(f"Function arguments are not a valid JSON object: {arguments}")
46
+ log_error(f"Function arguments are not a valid JSON object: {arguments}")
48
47
  function_call.error = "Function arguments are not a valid JSON object.\n\n Please fix and retry."
49
48
  return function_call
50
49
 
@@ -66,31 +65,102 @@ def get_function_call(
66
65
 
67
66
  function_call.arguments = clean_arguments
68
67
  except Exception as e:
69
- logger.error(f"Unable to parsing function arguments:\n{arguments}\nError: {e}")
68
+ log_error(f"Unable to parsing function arguments:\n{arguments}\nError: {e}")
70
69
  function_call.error = f"Error while parsing function arguments: {e}\n\n Please fix and retry."
71
70
  return function_call
72
71
  return function_call
73
72
 
74
73
 
75
- # def run_function(func, *args, **kwargs):
76
- # if asyncio.iscoroutinefunction(func):
77
- # logger.debug("Running asynchronous function")
78
- # try:
79
- # loop = asyncio.get_running_loop()
80
- # except RuntimeError as e: # No running event loop
81
- # logger.debug(f"Could not get running event loop: {e}")
82
- # logger.debug("Running with a new event loop")
83
- # loop = asyncio.new_event_loop()
84
- # asyncio.set_event_loop(loop)
85
- # result = loop.run_until_complete(func(*args, **kwargs))
86
- # loop.close()
87
- # logger.debug("Done running with a new event loop")
88
- # return result
89
- # else: # There is a running event loop
90
- # logger.debug("Running in existing event loop")
91
- # result = loop.run_until_complete(func(*args, **kwargs))
92
- # logger.debug("Done running in existing event loop")
93
- # return result
94
- # else: # The function is a synchronous function
95
- # logger.debug("Running synchronous function")
96
- # return func(*args, **kwargs)
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