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/hooks.py ADDED
@@ -0,0 +1,171 @@
1
+ from copy import deepcopy
2
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Union
3
+
4
+ if TYPE_CHECKING:
5
+ from agno.eval.base import BaseEval
6
+
7
+ from agno.guardrails.base import BaseGuardrail
8
+ from agno.hooks.decorator import HOOK_RUN_IN_BACKGROUND_ATTR
9
+ from agno.utils.log import log_warning
10
+
11
+ # Keys that should be deep copied for background hooks to prevent race conditions
12
+ BACKGROUND_HOOK_COPY_KEYS = frozenset(
13
+ {"run_input", "run_context", "run_output", "session_state", "dependencies", "metadata"}
14
+ )
15
+
16
+
17
+ def copy_args_for_background(args: Dict[str, Any]) -> Dict[str, Any]:
18
+ """
19
+ Create a copy of hook arguments for background execution.
20
+
21
+ This deep copies run_input, run_context, run_output, session_state, dependencies,
22
+ and metadata to prevent race conditions when hooks run in the background.
23
+
24
+ Args:
25
+ args: The original arguments dictionary
26
+
27
+ Returns:
28
+ A new dictionary with copied values for sensitive keys
29
+ """
30
+ copied_args = {}
31
+ for key, value in args.items():
32
+ if key in BACKGROUND_HOOK_COPY_KEYS and value is not None:
33
+ try:
34
+ copied_args[key] = deepcopy(value)
35
+ except Exception:
36
+ # If deepcopy fails (e.g., for non-copyable objects), use the original
37
+ log_warning(f"Could not deepcopy {key} for background hook, using original reference")
38
+ copied_args[key] = value
39
+ else:
40
+ copied_args[key] = value
41
+ return copied_args
42
+
43
+
44
+ def should_run_hook_in_background(hook: Callable[..., Any]) -> bool:
45
+ """
46
+ Check if a hook function should run in background.
47
+
48
+ This checks for the _agno_run_in_background attribute set by the @hook decorator.
49
+
50
+ Args:
51
+ hook: The hook function to check
52
+
53
+ Returns:
54
+ True if the hook is decorated with @hook(run_in_background=True)
55
+ """
56
+ return getattr(hook, HOOK_RUN_IN_BACKGROUND_ATTR, False)
57
+
58
+
59
+ def normalize_pre_hooks(
60
+ hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail, "BaseEval"]]],
61
+ async_mode: bool = False,
62
+ ) -> Optional[List[Callable[..., Any]]]:
63
+ """Normalize pre-hooks to a list format.
64
+
65
+ Args:
66
+ hooks: List of hook functions, guardrails, or eval instances
67
+ async_mode: Whether to use async versions of methods
68
+ """
69
+ from agno.eval.base import BaseEval
70
+
71
+ result_hooks: List[Callable[..., Any]] = []
72
+
73
+ if hooks is not None:
74
+ for hook in hooks:
75
+ if isinstance(hook, BaseGuardrail):
76
+ if async_mode:
77
+ result_hooks.append(hook.async_check)
78
+ else:
79
+ result_hooks.append(hook.check)
80
+ elif isinstance(hook, BaseEval):
81
+ # Extract pre_check method
82
+ method = hook.async_pre_check if async_mode else hook.pre_check
83
+
84
+ from functools import partial
85
+
86
+ wrapped = partial(method)
87
+ wrapped.__name__ = method.__name__ # type: ignore
88
+ setattr(wrapped, HOOK_RUN_IN_BACKGROUND_ATTR, getattr(hook, "run_in_background", False))
89
+ result_hooks.append(wrapped)
90
+ else:
91
+ # Check if the hook is async and used within sync methods
92
+ if not async_mode:
93
+ import asyncio
94
+
95
+ if asyncio.iscoroutinefunction(hook):
96
+ raise ValueError(
97
+ f"Cannot use {hook.__name__} (an async hook) with `run()`. Use `arun()` instead."
98
+ )
99
+
100
+ result_hooks.append(hook)
101
+ return result_hooks if result_hooks else None
102
+
103
+
104
+ def normalize_post_hooks(
105
+ hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail, "BaseEval"]]],
106
+ async_mode: bool = False,
107
+ ) -> Optional[List[Callable[..., Any]]]:
108
+ """Normalize post-hooks to a list format.
109
+
110
+ Args:
111
+ hooks: List of hook functions, guardrails, or eval instances
112
+ async_mode: Whether to use async versions of methods
113
+ """
114
+ from agno.eval.base import BaseEval
115
+
116
+ result_hooks: List[Callable[..., Any]] = []
117
+
118
+ if hooks is not None:
119
+ for hook in hooks:
120
+ if isinstance(hook, BaseGuardrail):
121
+ if async_mode:
122
+ result_hooks.append(hook.async_check)
123
+ else:
124
+ result_hooks.append(hook.check)
125
+ elif isinstance(hook, BaseEval):
126
+ # Extract post_check method
127
+ method = hook.async_post_check if async_mode else hook.post_check # type: ignore[assignment]
128
+
129
+ from functools import partial
130
+
131
+ wrapped = partial(method)
132
+ wrapped.__name__ = method.__name__ # type: ignore
133
+ setattr(wrapped, HOOK_RUN_IN_BACKGROUND_ATTR, getattr(hook, "run_in_background", False))
134
+ result_hooks.append(wrapped)
135
+ else:
136
+ # Check if the hook is async and used within sync methods
137
+ if not async_mode:
138
+ import asyncio
139
+
140
+ if asyncio.iscoroutinefunction(hook):
141
+ raise ValueError(
142
+ f"Cannot use {hook.__name__} (an async hook) with `run()`. Use `arun()` instead."
143
+ )
144
+
145
+ result_hooks.append(hook)
146
+ return result_hooks if result_hooks else None
147
+
148
+
149
+ def filter_hook_args(hook: Callable[..., Any], all_args: Dict[str, Any]) -> Dict[str, Any]:
150
+ """Filter arguments to only include those that the hook function accepts."""
151
+ import inspect
152
+
153
+ try:
154
+ sig = inspect.signature(hook)
155
+ accepted_params = set(sig.parameters.keys())
156
+
157
+ has_var_keyword = any(param.kind == inspect.Parameter.VAR_KEYWORD for param in sig.parameters.values())
158
+
159
+ # If the function has **kwargs, pass all arguments
160
+ if has_var_keyword:
161
+ return all_args
162
+
163
+ # Otherwise, filter to only include accepted parameters
164
+ filtered_args = {key: value for key, value in all_args.items() if key in accepted_params}
165
+
166
+ return filtered_args
167
+
168
+ except Exception as e:
169
+ log_warning(f"Could not inspect hook signature, passing all arguments: {e}")
170
+ # If signature inspection fails, pass all arguments as fallback
171
+ return all_args
agno/utils/http.py ADDED
@@ -0,0 +1,185 @@
1
+ import asyncio
2
+ import logging
3
+ from time import sleep
4
+ from typing import Optional
5
+
6
+ import httpx
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ DEFAULT_MAX_RETRIES = 3
11
+ DEFAULT_BACKOFF_FACTOR = 2 # Exponential backoff: 1, 2, 4, 8...
12
+
13
+ # Global httpx clients for resource efficiency
14
+ # These are shared across all models to reuse connection pools and avoid resource leaks.
15
+ # Consumers can override these at application startup using set_default_sync_client()
16
+ # and set_default_async_client() to customize limits, timeouts, proxies, etc.
17
+ _global_sync_client: Optional[httpx.Client] = None
18
+ _global_async_client: Optional[httpx.AsyncClient] = None
19
+
20
+
21
+ def get_default_sync_client() -> httpx.Client:
22
+ """Get or create the global synchronous httpx client.
23
+
24
+ Returns:
25
+ A singleton httpx.Client instance with default limits.
26
+ """
27
+ global _global_sync_client
28
+ if _global_sync_client is None or _global_sync_client.is_closed:
29
+ _global_sync_client = httpx.Client(
30
+ limits=httpx.Limits(max_connections=1000, max_keepalive_connections=200), http2=True, follow_redirects=True
31
+ )
32
+ return _global_sync_client
33
+
34
+
35
+ def get_default_async_client() -> httpx.AsyncClient:
36
+ """Get or create the global asynchronous httpx client.
37
+
38
+ Returns:
39
+ A singleton httpx.AsyncClient instance with default limits.
40
+ """
41
+ global _global_async_client
42
+ if _global_async_client is None or _global_async_client.is_closed:
43
+ _global_async_client = httpx.AsyncClient(
44
+ limits=httpx.Limits(max_connections=1000, max_keepalive_connections=200), http2=True, follow_redirects=True
45
+ )
46
+ return _global_async_client
47
+
48
+
49
+ def close_sync_client() -> None:
50
+ """Closes the global sync httpx client.
51
+
52
+ Should be called during application shutdown.
53
+ """
54
+ global _global_sync_client
55
+ if _global_sync_client is not None and not _global_sync_client.is_closed:
56
+ _global_sync_client.close()
57
+
58
+
59
+ async def aclose_default_clients() -> None:
60
+ """Asynchronously close the global httpx clients.
61
+
62
+ Should be called during application shutdown in async contexts.
63
+ """
64
+ global _global_sync_client, _global_async_client
65
+ if _global_sync_client is not None and not _global_sync_client.is_closed:
66
+ _global_sync_client.close()
67
+ if _global_async_client is not None and not _global_async_client.is_closed:
68
+ await _global_async_client.aclose()
69
+
70
+
71
+ def set_default_sync_client(client: httpx.Client) -> None:
72
+ """Set the global synchronous httpx client.
73
+
74
+ IMPORTANT: Call before creating any model instances. Models cache clients on first use.
75
+
76
+ Allows consumers to override the default httpx client with custom configuration
77
+ (e.g., custom limits, timeouts, proxies, SSL verification, etc.).
78
+ This is useful at application startup to customize how all models connect.
79
+
80
+ Example:
81
+ >>> import httpx
82
+ >>> from agno.utils.http import set_default_sync_client
83
+ >>> custom_client = httpx.Client(
84
+ ... limits=httpx.Limits(max_connections=500),
85
+ ... timeout=httpx.Timeout(30.0),
86
+ ... verify=False # for dev environments
87
+ ... )
88
+ >>> set_default_sync_client(custom_client)
89
+ >>> # All models will now use this custom client
90
+
91
+ Args:
92
+ client: An httpx.Client instance to use as the global sync client.
93
+ """
94
+ global _global_sync_client
95
+ _global_sync_client = client
96
+
97
+
98
+ def set_default_async_client(client: httpx.AsyncClient) -> None:
99
+ """Set the global asynchronous httpx client.
100
+
101
+ IMPORTANT: Call before creating any model instances. Models cache clients on first use.
102
+
103
+ Allows consumers to override the default async httpx client with custom configuration
104
+ (e.g., custom limits, timeouts, proxies, SSL verification, etc.).
105
+ This is useful at application startup to customize how all models connect.
106
+
107
+ Example:
108
+ >>> import httpx
109
+ >>> from agno.utils.http import set_default_async_client
110
+ >>> custom_client = httpx.AsyncClient(
111
+ ... limits=httpx.Limits(max_connections=500),
112
+ ... timeout=httpx.Timeout(30.0),
113
+ ... verify=False # for dev environments
114
+ ... )
115
+ >>> set_default_async_client(custom_client)
116
+ >>> # All models will now use this custom client
117
+
118
+ Args:
119
+ client: An httpx.AsyncClient instance to use as the global async client.
120
+ """
121
+ global _global_async_client
122
+ _global_async_client = client
123
+
124
+
125
+ def fetch_with_retry(
126
+ url: str,
127
+ max_retries: int = DEFAULT_MAX_RETRIES,
128
+ backoff_factor: int = DEFAULT_BACKOFF_FACTOR,
129
+ proxy: Optional[str] = None,
130
+ ) -> httpx.Response:
131
+ """Synchronous HTTP GET with retry logic."""
132
+
133
+ for attempt in range(max_retries):
134
+ try:
135
+ response = httpx.get(url, proxy=proxy) if proxy else httpx.get(url)
136
+ response.raise_for_status()
137
+ return response
138
+ except httpx.RequestError as e:
139
+ if attempt == max_retries - 1:
140
+ logger.error(f"Failed to fetch {url} after {max_retries} attempts: {e}")
141
+ raise
142
+ wait_time = backoff_factor**attempt
143
+ logger.warning("Connection error.")
144
+ sleep(wait_time)
145
+ except httpx.HTTPStatusError as e:
146
+ logger.error(f"HTTP error for {url}: {e.response.status_code} - {e.response.text}")
147
+ raise
148
+
149
+ raise httpx.RequestError(f"Failed to fetch {url} after {max_retries} attempts")
150
+
151
+
152
+ async def async_fetch_with_retry(
153
+ url: str,
154
+ client: Optional[httpx.AsyncClient] = None,
155
+ max_retries: int = DEFAULT_MAX_RETRIES,
156
+ backoff_factor: int = DEFAULT_BACKOFF_FACTOR,
157
+ proxy: Optional[str] = None,
158
+ ) -> httpx.Response:
159
+ """Asynchronous HTTP GET with retry logic."""
160
+
161
+ async def _fetch():
162
+ if client is None:
163
+ client_args = {"proxy": proxy} if proxy else {}
164
+ async with httpx.AsyncClient(**client_args) as local_client: # type: ignore
165
+ return await local_client.get(url)
166
+ else:
167
+ return await client.get(url)
168
+
169
+ for attempt in range(max_retries):
170
+ try:
171
+ response = await _fetch()
172
+ response.raise_for_status()
173
+ return response
174
+ except httpx.RequestError as e:
175
+ if attempt == max_retries - 1:
176
+ logger.error(f"Failed to fetch {url} after {max_retries} attempts: {e}")
177
+ raise
178
+ wait_time = backoff_factor**attempt
179
+ logger.warning("Connection error.")
180
+ await asyncio.sleep(wait_time)
181
+ except httpx.HTTPStatusError as e:
182
+ logger.error(f"HTTP error for {url}: {e.response.status_code} - {e.response.text}")
183
+ raise
184
+
185
+ raise httpx.RequestError(f"Failed to fetch {url} after {max_retries} attempts")
agno/utils/json_schema.py CHANGED
@@ -1,15 +1,29 @@
1
+ from enum import Enum
1
2
  from typing import Any, Dict, Optional, Union, get_args, get_origin
2
3
 
4
+ from pydantic import BaseModel
5
+
3
6
  from agno.utils.log import logger
4
7
 
5
8
 
9
+ def is_origin_union_type(origin: Any) -> bool:
10
+ import sys
11
+
12
+ if sys.version_info.minor >= 10:
13
+ from types import UnionType # type: ignore
14
+
15
+ return origin in [Union, UnionType]
16
+
17
+ return origin is Union
18
+
19
+
6
20
  def get_json_type_for_py_type(arg: str) -> str:
7
21
  """
8
22
  Get the JSON schema type for a given type.
9
23
  :param arg: The type to get the JSON schema type for.
10
24
  :return: The JSON schema type.
11
25
  """
12
- # logger.info(f"Getting JSON type for: {arg}")
26
+ # log_info(f"Getting JSON type for: {arg}")
13
27
  if arg in ("int", "float", "complex", "Decimal"):
14
28
  return "number"
15
29
  elif arg in ("str", "string"):
@@ -27,13 +41,86 @@ def get_json_type_for_py_type(arg: str) -> str:
27
41
  return "object"
28
42
 
29
43
 
30
- def get_json_schema_for_arg(t: Any) -> Optional[Dict[str, Any]]:
31
- # logger.info(f"Getting JSON schema for arg: {t}")
32
- type_args = get_args(t)
33
- # logger.info(f"Type args: {type_args}")
34
- type_origin = get_origin(t)
35
- # logger.info(f"Type origin: {type_origin}")
44
+ def inline_pydantic_schema(schema: Dict[str, Any]) -> Dict[str, Any]:
45
+ """
46
+ Recursively inline Pydantic model schemas by replacing $ref with actual schema.
47
+ """
48
+ if not isinstance(schema, dict):
49
+ return schema
50
+
51
+ def resolve_ref(ref: str, defs: Dict[str, Any]) -> Dict[str, Any]:
52
+ """Resolve a $ref to its actual schema."""
53
+ if not ref.startswith("#/$defs/"):
54
+ return {"type": "object"} # Fallback for external refs
55
+
56
+ def_name = ref.split("/")[-1]
57
+ if def_name in defs:
58
+ return defs[def_name]
59
+ return {"type": "object"} # Fallback if definition not found
60
+
61
+ def process_schema(s: Dict[str, Any], defs: Dict[str, Any]) -> Dict[str, Any]:
62
+ """Process a schema dictionary, resolving all references."""
63
+ if not isinstance(s, dict):
64
+ return s
65
+
66
+ # Handle $ref
67
+ if "$ref" in s:
68
+ return resolve_ref(s["$ref"], defs)
69
+
70
+ # Create a new dict to avoid modifying the input
71
+ result = s.copy()
72
+
73
+ # Handle arrays
74
+ if "items" in result:
75
+ result["items"] = process_schema(result["items"], defs)
76
+
77
+ # Handle object properties
78
+ if "properties" in result:
79
+ for prop_name, prop_schema in result["properties"].items():
80
+ result["properties"][prop_name] = process_schema(prop_schema, defs)
81
+
82
+ # Handle anyOf (for Union types)
83
+ if "anyOf" in result:
84
+ result["anyOf"] = [process_schema(sub_schema, defs) for sub_schema in result["anyOf"]]
85
+
86
+ # Handle allOf (for inheritance)
87
+ if "allOf" in result:
88
+ result["allOf"] = [process_schema(sub_schema, defs) for sub_schema in result["allOf"]]
36
89
 
90
+ # Handle additionalProperties
91
+ if "additionalProperties" in result:
92
+ result["additionalProperties"] = process_schema(result["additionalProperties"], defs)
93
+
94
+ # Handle propertyNames
95
+ if "propertyNames" in result:
96
+ result["propertyNames"] = process_schema(result["propertyNames"], defs)
97
+
98
+ return result
99
+
100
+ # Store definitions for later use
101
+ definitions = schema.pop("$defs", {})
102
+
103
+ # First, resolve any nested references in definitions
104
+ resolved_definitions = {}
105
+ for def_name, def_schema in definitions.items():
106
+ resolved_definitions[def_name] = process_schema(def_schema, definitions)
107
+
108
+ # Process the main schema with resolved definitions
109
+ result = process_schema(schema, resolved_definitions)
110
+
111
+ # Remove any remaining definitions
112
+ if "$defs" in result:
113
+ del result["$defs"]
114
+
115
+ return result
116
+
117
+
118
+ def get_json_schema_for_arg(type_hint: Any) -> Optional[Dict[str, Any]]:
119
+ # log_info(f"Getting JSON schema for arg: {t}")
120
+ type_args = get_args(type_hint)
121
+ # log_info(f"Type args: {type_args}")
122
+ type_origin = get_origin(type_hint)
123
+ # log_info(f"Type origin: {type_origin}")
37
124
  if type_origin is not None:
38
125
  if type_origin in (list, tuple, set, frozenset):
39
126
  json_schema_for_items = get_json_schema_for_arg(type_args[0]) if type_args else {"type": "string"}
@@ -43,19 +130,61 @@ def get_json_schema_for_arg(t: Any) -> Optional[Dict[str, Any]]:
43
130
  key_schema = get_json_schema_for_arg(type_args[0]) if type_args else {"type": "string"}
44
131
  value_schema = get_json_schema_for_arg(type_args[1]) if len(type_args) > 1 else {"type": "string"}
45
132
  return {"type": "object", "propertyNames": key_schema, "additionalProperties": value_schema}
46
- elif type_origin is Union:
133
+ elif is_origin_union_type(type_origin):
47
134
  types = []
48
135
  for arg in type_args:
49
- if arg is not type(None):
50
- try:
51
- schema = get_json_schema_for_arg(arg)
52
- if schema:
53
- types.append(schema)
54
- except Exception:
55
- continue
136
+ try:
137
+ schema = get_json_schema_for_arg(arg)
138
+ if schema:
139
+ types.append(schema)
140
+ except Exception:
141
+ continue
56
142
  return {"anyOf": types} if types else None
57
143
 
58
- return {"type": get_json_type_for_py_type(t.__name__)}
144
+ if isinstance(type_hint, type) and issubclass(type_hint, Enum):
145
+ enum_values = [member.value for member in type_hint]
146
+ return {"type": "string", "enum": enum_values}
147
+
148
+ if isinstance(type_hint, type) and issubclass(type_hint, BaseModel):
149
+ # Get the schema and inline it
150
+ schema = type_hint.model_json_schema()
151
+ return inline_pydantic_schema(schema) # type: ignore
152
+
153
+ if hasattr(type_hint, "__dataclass_fields__"):
154
+ # Convert dataclass to JSON schema
155
+ properties = {}
156
+ required = []
157
+
158
+ for field_name, field in type_hint.__dataclass_fields__.items():
159
+ field_type = field.type
160
+ field_schema = get_json_schema_for_arg(field_type)
161
+
162
+ if (
163
+ field_schema
164
+ and "anyOf" in field_schema
165
+ and any(schema["type"] == "null" for schema in field_schema["anyOf"])
166
+ ):
167
+ field_schema["type"] = next(
168
+ schema["type"] for schema in field_schema["anyOf"] if schema["type"] != "null"
169
+ )
170
+ field_schema.pop("anyOf")
171
+ else:
172
+ required.append(field_name)
173
+
174
+ if field_schema:
175
+ properties[field_name] = field_schema
176
+
177
+ arg_json_schema = {"type": "object", "properties": properties, "additionalProperties": False}
178
+
179
+ if required:
180
+ arg_json_schema["required"] = required
181
+ return arg_json_schema
182
+
183
+ json_schema: Dict[str, Any] = {"type": get_json_type_for_py_type(type_hint.__name__)}
184
+ if json_schema["type"] == "object":
185
+ json_schema["properties"] = {}
186
+ json_schema["additionalProperties"] = False
187
+ return json_schema
59
188
 
60
189
 
61
190
  def get_json_schema(
@@ -68,45 +197,38 @@ def get_json_schema(
68
197
  if strict:
69
198
  json_schema["additionalProperties"] = False
70
199
 
71
- for k, v in type_hints.items():
72
- # logger.info(f"Parsing arg: {k} | {v}")
73
- if k == "return":
200
+ # We only include the fields in the type_hints dict
201
+ for parameter_name, type_hint in type_hints.items():
202
+ # log_info(f"Parsing arg: {k} | {v}")
203
+ if parameter_name == "return":
74
204
  continue
75
205
 
76
206
  try:
77
207
  # Check if type is Optional (Union with NoneType)
78
- type_origin = get_origin(v)
79
- type_args = get_args(v)
208
+ type_origin = get_origin(type_hint)
209
+ type_args = get_args(type_hint)
80
210
  is_optional = type_origin is Union and len(type_args) == 2 and any(arg is type(None) for arg in type_args)
81
211
 
82
212
  # Get the actual type if it's Optional
83
213
  if is_optional:
84
- v = next(arg for arg in type_args if arg is not type(None))
214
+ type_hint = next(arg for arg in type_args if arg is not type(None))
85
215
 
86
- # Handle cases with no type hint
87
- if v:
88
- arg_json_schema = get_json_schema_for_arg(v)
216
+ if type_hint:
217
+ arg_json_schema = get_json_schema_for_arg(type_hint)
89
218
  else:
90
219
  arg_json_schema = {}
91
220
 
92
221
  if arg_json_schema is not None:
93
- if is_optional:
94
- # Handle null type for optional fields
95
- if isinstance(arg_json_schema["type"], list):
96
- arg_json_schema["type"].append("null")
97
- else:
98
- arg_json_schema["type"] = [arg_json_schema["type"], "null"]
99
-
100
222
  # Add description
101
- if param_descriptions and k in param_descriptions and param_descriptions[k]:
102
- arg_json_schema["description"] = param_descriptions[k]
223
+ if param_descriptions and parameter_name in param_descriptions and param_descriptions[parameter_name]:
224
+ arg_json_schema["description"] = param_descriptions[parameter_name]
103
225
 
104
- json_schema["properties"][k] = arg_json_schema
226
+ json_schema["properties"][parameter_name] = arg_json_schema
105
227
 
106
228
  else:
107
- logger.warning(f"Could not parse argument {k} of type {v}")
229
+ logger.warning(f"Could not parse argument {parameter_name} of type {type_hint}")
108
230
  except Exception as e:
109
- logger.error(f"Error processing argument {k}: {str(e)}")
231
+ logger.error(f"Error processing argument {parameter_name}: {str(e)}")
110
232
  continue
111
233
 
112
234
  return json_schema
@@ -0,0 +1,36 @@
1
+ from typing import Any, Dict, List, Optional, Union
2
+
3
+ from agno.filters import FilterExpr
4
+ from agno.utils.log import log_info
5
+
6
+
7
+ def get_agentic_or_user_search_filters(
8
+ filters: Optional[Dict[str, Any]], effective_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]]
9
+ ) -> Dict[str, Any]:
10
+ """Helper function to determine the final filters to use for the search.
11
+
12
+ Args:
13
+ filters: Filters passed by the agent.
14
+ effective_filters: Filters passed by user.
15
+
16
+ Returns:
17
+ Dict[str, Any]: The final filters to use for the search.
18
+ """
19
+ search_filters = None
20
+
21
+ # If agentic filters exist and manual filters (passed by user) do not, use agentic filters
22
+ if filters and not effective_filters:
23
+ search_filters = filters
24
+
25
+ # If both agentic filters exist and manual filters (passed by user) exist, use manual filters (give priority to user and override)
26
+ if filters and effective_filters:
27
+ if isinstance(effective_filters, dict):
28
+ search_filters = effective_filters
29
+ elif isinstance(effective_filters, list):
30
+ # If effective_filters is a list (likely List[FilterExpr]), convert both filters and effective_filters to a dict if possible, otherwise raise
31
+ raise ValueError(
32
+ "Merging dict and list of filters is not supported; effective_filters should be a dict for search compatibility."
33
+ )
34
+
35
+ log_info(f"Filters used by Agent: {search_filters}")
36
+ return search_filters or {}
agno/utils/location.py ADDED
@@ -0,0 +1,19 @@
1
+ from typing import Any, Dict
2
+
3
+ import requests
4
+
5
+ from agno.utils.log import log_warning
6
+
7
+
8
+ def get_location() -> Dict[str, Any]:
9
+ """Get approximate location using IP geolocation."""
10
+ try:
11
+ response = requests.get("https://api.ipify.org?format=json", timeout=5)
12
+ ip = response.json()["ip"]
13
+ response = requests.get(f"http://ip-api.com/json/{ip}", timeout=5)
14
+ if response.status_code == 200:
15
+ data = response.json()
16
+ return {"city": data.get("city"), "region": data.get("region"), "country": data.get("country")}
17
+ except Exception as e:
18
+ log_warning(f"Failed to get location: {e}")
19
+ return {}