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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (723) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +44 -5
  3. agno/agent/agent.py +10531 -2975
  4. agno/api/agent.py +14 -53
  5. agno/api/api.py +7 -46
  6. agno/api/evals.py +22 -0
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -25
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +6 -9
  11. agno/api/schemas/evals.py +16 -0
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +10 -10
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +16 -0
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +22 -26
  18. agno/api/workflow.py +28 -0
  19. agno/cloud/aws/base.py +214 -0
  20. agno/cloud/aws/s3/__init__.py +2 -0
  21. agno/cloud/aws/s3/api_client.py +43 -0
  22. agno/cloud/aws/s3/bucket.py +195 -0
  23. agno/cloud/aws/s3/object.py +57 -0
  24. agno/compression/__init__.py +3 -0
  25. agno/compression/manager.py +247 -0
  26. agno/culture/__init__.py +3 -0
  27. agno/culture/manager.py +956 -0
  28. agno/db/__init__.py +24 -0
  29. agno/db/async_postgres/__init__.py +3 -0
  30. agno/db/base.py +946 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2781 -0
  33. agno/db/dynamo/schemas.py +442 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +2379 -0
  37. agno/db/firestore/schemas.py +181 -0
  38. agno/db/firestore/utils.py +376 -0
  39. agno/db/gcs_json/__init__.py +3 -0
  40. agno/db/gcs_json/gcs_json_db.py +1791 -0
  41. agno/db/gcs_json/utils.py +228 -0
  42. agno/db/in_memory/__init__.py +3 -0
  43. agno/db/in_memory/in_memory_db.py +1312 -0
  44. agno/db/in_memory/utils.py +230 -0
  45. agno/db/json/__init__.py +3 -0
  46. agno/db/json/json_db.py +1777 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/manager.py +199 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/migrations/versions/v2_3_0.py +938 -0
  51. agno/db/mongo/__init__.py +17 -0
  52. agno/db/mongo/async_mongo.py +2760 -0
  53. agno/db/mongo/mongo.py +2597 -0
  54. agno/db/mongo/schemas.py +119 -0
  55. agno/db/mongo/utils.py +276 -0
  56. agno/db/mysql/__init__.py +4 -0
  57. agno/db/mysql/async_mysql.py +2912 -0
  58. agno/db/mysql/mysql.py +2923 -0
  59. agno/db/mysql/schemas.py +186 -0
  60. agno/db/mysql/utils.py +488 -0
  61. agno/db/postgres/__init__.py +4 -0
  62. agno/db/postgres/async_postgres.py +2579 -0
  63. agno/db/postgres/postgres.py +2870 -0
  64. agno/db/postgres/schemas.py +187 -0
  65. agno/db/postgres/utils.py +442 -0
  66. agno/db/redis/__init__.py +3 -0
  67. agno/db/redis/redis.py +2141 -0
  68. agno/db/redis/schemas.py +159 -0
  69. agno/db/redis/utils.py +346 -0
  70. agno/db/schemas/__init__.py +4 -0
  71. agno/db/schemas/culture.py +120 -0
  72. agno/db/schemas/evals.py +34 -0
  73. agno/db/schemas/knowledge.py +40 -0
  74. agno/db/schemas/memory.py +61 -0
  75. agno/db/singlestore/__init__.py +3 -0
  76. agno/db/singlestore/schemas.py +179 -0
  77. agno/db/singlestore/singlestore.py +2877 -0
  78. agno/db/singlestore/utils.py +384 -0
  79. agno/db/sqlite/__init__.py +4 -0
  80. agno/db/sqlite/async_sqlite.py +2911 -0
  81. agno/db/sqlite/schemas.py +181 -0
  82. agno/db/sqlite/sqlite.py +2908 -0
  83. agno/db/sqlite/utils.py +429 -0
  84. agno/db/surrealdb/__init__.py +3 -0
  85. agno/db/surrealdb/metrics.py +292 -0
  86. agno/db/surrealdb/models.py +334 -0
  87. agno/db/surrealdb/queries.py +71 -0
  88. agno/db/surrealdb/surrealdb.py +1908 -0
  89. agno/db/surrealdb/utils.py +147 -0
  90. agno/db/utils.py +118 -0
  91. agno/eval/__init__.py +24 -0
  92. agno/eval/accuracy.py +666 -276
  93. agno/eval/agent_as_judge.py +861 -0
  94. agno/eval/base.py +29 -0
  95. agno/eval/performance.py +779 -0
  96. agno/eval/reliability.py +241 -62
  97. agno/eval/utils.py +120 -0
  98. agno/exceptions.py +143 -1
  99. agno/filters.py +354 -0
  100. agno/guardrails/__init__.py +6 -0
  101. agno/guardrails/base.py +19 -0
  102. agno/guardrails/openai.py +144 -0
  103. agno/guardrails/pii.py +94 -0
  104. agno/guardrails/prompt_injection.py +52 -0
  105. agno/hooks/__init__.py +3 -0
  106. agno/hooks/decorator.py +164 -0
  107. agno/integrations/discord/__init__.py +3 -0
  108. agno/integrations/discord/client.py +203 -0
  109. agno/knowledge/__init__.py +5 -1
  110. agno/{document → knowledge}/chunking/agentic.py +22 -14
  111. agno/{document → knowledge}/chunking/document.py +2 -2
  112. agno/{document → knowledge}/chunking/fixed.py +7 -6
  113. agno/knowledge/chunking/markdown.py +151 -0
  114. agno/{document → knowledge}/chunking/recursive.py +15 -3
  115. agno/knowledge/chunking/row.py +39 -0
  116. agno/knowledge/chunking/semantic.py +91 -0
  117. agno/knowledge/chunking/strategy.py +165 -0
  118. agno/knowledge/content.py +74 -0
  119. agno/knowledge/document/__init__.py +5 -0
  120. agno/{document → knowledge/document}/base.py +12 -2
  121. agno/knowledge/embedder/__init__.py +5 -0
  122. agno/knowledge/embedder/aws_bedrock.py +343 -0
  123. agno/knowledge/embedder/azure_openai.py +210 -0
  124. agno/{embedder → knowledge/embedder}/base.py +8 -0
  125. agno/knowledge/embedder/cohere.py +323 -0
  126. agno/knowledge/embedder/fastembed.py +62 -0
  127. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  128. agno/knowledge/embedder/google.py +258 -0
  129. agno/knowledge/embedder/huggingface.py +94 -0
  130. agno/knowledge/embedder/jina.py +182 -0
  131. agno/knowledge/embedder/langdb.py +22 -0
  132. agno/knowledge/embedder/mistral.py +206 -0
  133. agno/knowledge/embedder/nebius.py +13 -0
  134. agno/knowledge/embedder/ollama.py +154 -0
  135. agno/knowledge/embedder/openai.py +195 -0
  136. agno/knowledge/embedder/sentence_transformer.py +63 -0
  137. agno/{embedder → knowledge/embedder}/together.py +1 -1
  138. agno/knowledge/embedder/vllm.py +262 -0
  139. agno/knowledge/embedder/voyageai.py +165 -0
  140. agno/knowledge/knowledge.py +3006 -0
  141. agno/knowledge/reader/__init__.py +7 -0
  142. agno/knowledge/reader/arxiv_reader.py +81 -0
  143. agno/knowledge/reader/base.py +95 -0
  144. agno/knowledge/reader/csv_reader.py +164 -0
  145. agno/knowledge/reader/docx_reader.py +82 -0
  146. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  147. agno/knowledge/reader/firecrawl_reader.py +201 -0
  148. agno/knowledge/reader/json_reader.py +88 -0
  149. agno/knowledge/reader/markdown_reader.py +137 -0
  150. agno/knowledge/reader/pdf_reader.py +431 -0
  151. agno/knowledge/reader/pptx_reader.py +101 -0
  152. agno/knowledge/reader/reader_factory.py +313 -0
  153. agno/knowledge/reader/s3_reader.py +89 -0
  154. agno/knowledge/reader/tavily_reader.py +193 -0
  155. agno/knowledge/reader/text_reader.py +127 -0
  156. agno/knowledge/reader/web_search_reader.py +325 -0
  157. agno/knowledge/reader/website_reader.py +455 -0
  158. agno/knowledge/reader/wikipedia_reader.py +91 -0
  159. agno/knowledge/reader/youtube_reader.py +78 -0
  160. agno/knowledge/remote_content/remote_content.py +88 -0
  161. agno/knowledge/reranker/__init__.py +3 -0
  162. agno/{reranker → knowledge/reranker}/base.py +1 -1
  163. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  164. agno/knowledge/reranker/infinity.py +195 -0
  165. agno/knowledge/reranker/sentence_transformer.py +54 -0
  166. agno/knowledge/types.py +39 -0
  167. agno/knowledge/utils.py +234 -0
  168. agno/media.py +439 -95
  169. agno/memory/__init__.py +16 -3
  170. agno/memory/manager.py +1474 -123
  171. agno/memory/strategies/__init__.py +15 -0
  172. agno/memory/strategies/base.py +66 -0
  173. agno/memory/strategies/summarize.py +196 -0
  174. agno/memory/strategies/types.py +37 -0
  175. agno/models/aimlapi/__init__.py +5 -0
  176. agno/models/aimlapi/aimlapi.py +62 -0
  177. agno/models/anthropic/__init__.py +4 -0
  178. agno/models/anthropic/claude.py +960 -496
  179. agno/models/aws/__init__.py +15 -0
  180. agno/models/aws/bedrock.py +686 -451
  181. agno/models/aws/claude.py +190 -183
  182. agno/models/azure/__init__.py +18 -1
  183. agno/models/azure/ai_foundry.py +489 -0
  184. agno/models/azure/openai_chat.py +89 -40
  185. agno/models/base.py +2477 -550
  186. agno/models/cerebras/__init__.py +12 -0
  187. agno/models/cerebras/cerebras.py +565 -0
  188. agno/models/cerebras/cerebras_openai.py +131 -0
  189. agno/models/cohere/__init__.py +4 -0
  190. agno/models/cohere/chat.py +306 -492
  191. agno/models/cometapi/__init__.py +5 -0
  192. agno/models/cometapi/cometapi.py +74 -0
  193. agno/models/dashscope/__init__.py +5 -0
  194. agno/models/dashscope/dashscope.py +90 -0
  195. agno/models/deepinfra/__init__.py +5 -0
  196. agno/models/deepinfra/deepinfra.py +45 -0
  197. agno/models/deepseek/__init__.py +4 -0
  198. agno/models/deepseek/deepseek.py +110 -9
  199. agno/models/fireworks/__init__.py +4 -0
  200. agno/models/fireworks/fireworks.py +19 -22
  201. agno/models/google/__init__.py +3 -7
  202. agno/models/google/gemini.py +1717 -662
  203. agno/models/google/utils.py +22 -0
  204. agno/models/groq/__init__.py +4 -0
  205. agno/models/groq/groq.py +391 -666
  206. agno/models/huggingface/__init__.py +4 -0
  207. agno/models/huggingface/huggingface.py +266 -538
  208. agno/models/ibm/__init__.py +5 -0
  209. agno/models/ibm/watsonx.py +432 -0
  210. agno/models/internlm/__init__.py +3 -0
  211. agno/models/internlm/internlm.py +20 -3
  212. agno/models/langdb/__init__.py +1 -0
  213. agno/models/langdb/langdb.py +60 -0
  214. agno/models/litellm/__init__.py +14 -0
  215. agno/models/litellm/chat.py +503 -0
  216. agno/models/litellm/litellm_openai.py +42 -0
  217. agno/models/llama_cpp/__init__.py +5 -0
  218. agno/models/llama_cpp/llama_cpp.py +22 -0
  219. agno/models/lmstudio/__init__.py +5 -0
  220. agno/models/lmstudio/lmstudio.py +25 -0
  221. agno/models/message.py +361 -39
  222. agno/models/meta/__init__.py +12 -0
  223. agno/models/meta/llama.py +502 -0
  224. agno/models/meta/llama_openai.py +79 -0
  225. agno/models/metrics.py +120 -0
  226. agno/models/mistral/__init__.py +4 -0
  227. agno/models/mistral/mistral.py +293 -393
  228. agno/models/nebius/__init__.py +3 -0
  229. agno/models/nebius/nebius.py +53 -0
  230. agno/models/nexus/__init__.py +3 -0
  231. agno/models/nexus/nexus.py +22 -0
  232. agno/models/nvidia/__init__.py +4 -0
  233. agno/models/nvidia/nvidia.py +22 -3
  234. agno/models/ollama/__init__.py +4 -2
  235. agno/models/ollama/chat.py +257 -492
  236. agno/models/openai/__init__.py +7 -0
  237. agno/models/openai/chat.py +725 -770
  238. agno/models/openai/like.py +16 -2
  239. agno/models/openai/responses.py +1121 -0
  240. agno/models/openrouter/__init__.py +4 -0
  241. agno/models/openrouter/openrouter.py +62 -5
  242. agno/models/perplexity/__init__.py +5 -0
  243. agno/models/perplexity/perplexity.py +203 -0
  244. agno/models/portkey/__init__.py +3 -0
  245. agno/models/portkey/portkey.py +82 -0
  246. agno/models/requesty/__init__.py +5 -0
  247. agno/models/requesty/requesty.py +69 -0
  248. agno/models/response.py +177 -7
  249. agno/models/sambanova/__init__.py +4 -0
  250. agno/models/sambanova/sambanova.py +23 -4
  251. agno/models/siliconflow/__init__.py +5 -0
  252. agno/models/siliconflow/siliconflow.py +42 -0
  253. agno/models/together/__init__.py +4 -0
  254. agno/models/together/together.py +21 -164
  255. agno/models/utils.py +266 -0
  256. agno/models/vercel/__init__.py +3 -0
  257. agno/models/vercel/v0.py +43 -0
  258. agno/models/vertexai/__init__.py +0 -1
  259. agno/models/vertexai/claude.py +190 -0
  260. agno/models/vllm/__init__.py +3 -0
  261. agno/models/vllm/vllm.py +83 -0
  262. agno/models/xai/__init__.py +2 -0
  263. agno/models/xai/xai.py +111 -7
  264. agno/os/__init__.py +3 -0
  265. agno/os/app.py +1027 -0
  266. agno/os/auth.py +244 -0
  267. agno/os/config.py +126 -0
  268. agno/os/interfaces/__init__.py +1 -0
  269. agno/os/interfaces/a2a/__init__.py +3 -0
  270. agno/os/interfaces/a2a/a2a.py +42 -0
  271. agno/os/interfaces/a2a/router.py +249 -0
  272. agno/os/interfaces/a2a/utils.py +924 -0
  273. agno/os/interfaces/agui/__init__.py +3 -0
  274. agno/os/interfaces/agui/agui.py +47 -0
  275. agno/os/interfaces/agui/router.py +147 -0
  276. agno/os/interfaces/agui/utils.py +574 -0
  277. agno/os/interfaces/base.py +25 -0
  278. agno/os/interfaces/slack/__init__.py +3 -0
  279. agno/os/interfaces/slack/router.py +148 -0
  280. agno/os/interfaces/slack/security.py +30 -0
  281. agno/os/interfaces/slack/slack.py +47 -0
  282. agno/os/interfaces/whatsapp/__init__.py +3 -0
  283. agno/os/interfaces/whatsapp/router.py +210 -0
  284. agno/os/interfaces/whatsapp/security.py +55 -0
  285. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  286. agno/os/mcp.py +293 -0
  287. agno/os/middleware/__init__.py +9 -0
  288. agno/os/middleware/jwt.py +797 -0
  289. agno/os/router.py +258 -0
  290. agno/os/routers/__init__.py +3 -0
  291. agno/os/routers/agents/__init__.py +3 -0
  292. agno/os/routers/agents/router.py +599 -0
  293. agno/os/routers/agents/schema.py +261 -0
  294. agno/os/routers/evals/__init__.py +3 -0
  295. agno/os/routers/evals/evals.py +450 -0
  296. agno/os/routers/evals/schemas.py +174 -0
  297. agno/os/routers/evals/utils.py +231 -0
  298. agno/os/routers/health.py +31 -0
  299. agno/os/routers/home.py +52 -0
  300. agno/os/routers/knowledge/__init__.py +3 -0
  301. agno/os/routers/knowledge/knowledge.py +1008 -0
  302. agno/os/routers/knowledge/schemas.py +178 -0
  303. agno/os/routers/memory/__init__.py +3 -0
  304. agno/os/routers/memory/memory.py +661 -0
  305. agno/os/routers/memory/schemas.py +88 -0
  306. agno/os/routers/metrics/__init__.py +3 -0
  307. agno/os/routers/metrics/metrics.py +190 -0
  308. agno/os/routers/metrics/schemas.py +47 -0
  309. agno/os/routers/session/__init__.py +3 -0
  310. agno/os/routers/session/session.py +997 -0
  311. agno/os/routers/teams/__init__.py +3 -0
  312. agno/os/routers/teams/router.py +512 -0
  313. agno/os/routers/teams/schema.py +257 -0
  314. agno/os/routers/traces/__init__.py +3 -0
  315. agno/os/routers/traces/schemas.py +414 -0
  316. agno/os/routers/traces/traces.py +499 -0
  317. agno/os/routers/workflows/__init__.py +3 -0
  318. agno/os/routers/workflows/router.py +624 -0
  319. agno/os/routers/workflows/schema.py +75 -0
  320. agno/os/schema.py +534 -0
  321. agno/os/scopes.py +469 -0
  322. agno/{playground → os}/settings.py +7 -15
  323. agno/os/utils.py +973 -0
  324. agno/reasoning/anthropic.py +80 -0
  325. agno/reasoning/azure_ai_foundry.py +67 -0
  326. agno/reasoning/deepseek.py +63 -0
  327. agno/reasoning/default.py +97 -0
  328. agno/reasoning/gemini.py +73 -0
  329. agno/reasoning/groq.py +71 -0
  330. agno/reasoning/helpers.py +24 -1
  331. agno/reasoning/ollama.py +67 -0
  332. agno/reasoning/openai.py +86 -0
  333. agno/reasoning/step.py +2 -1
  334. agno/reasoning/vertexai.py +76 -0
  335. agno/run/__init__.py +6 -0
  336. agno/run/agent.py +822 -0
  337. agno/run/base.py +247 -0
  338. agno/run/cancel.py +81 -0
  339. agno/run/requirement.py +181 -0
  340. agno/run/team.py +767 -0
  341. agno/run/workflow.py +708 -0
  342. agno/session/__init__.py +10 -0
  343. agno/session/agent.py +260 -0
  344. agno/session/summary.py +265 -0
  345. agno/session/team.py +342 -0
  346. agno/session/workflow.py +501 -0
  347. agno/table.py +10 -0
  348. agno/team/__init__.py +37 -0
  349. agno/team/team.py +9536 -0
  350. agno/tools/__init__.py +7 -0
  351. agno/tools/agentql.py +120 -0
  352. agno/tools/airflow.py +22 -12
  353. agno/tools/api.py +122 -0
  354. agno/tools/apify.py +276 -83
  355. agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
  356. agno/tools/aws_lambda.py +28 -7
  357. agno/tools/aws_ses.py +66 -0
  358. agno/tools/baidusearch.py +11 -4
  359. agno/tools/bitbucket.py +292 -0
  360. agno/tools/brandfetch.py +213 -0
  361. agno/tools/bravesearch.py +106 -0
  362. agno/tools/brightdata.py +367 -0
  363. agno/tools/browserbase.py +209 -0
  364. agno/tools/calcom.py +32 -23
  365. agno/tools/calculator.py +24 -37
  366. agno/tools/cartesia.py +187 -0
  367. agno/tools/{clickup_tool.py → clickup.py} +17 -28
  368. agno/tools/confluence.py +91 -26
  369. agno/tools/crawl4ai.py +139 -43
  370. agno/tools/csv_toolkit.py +28 -22
  371. agno/tools/dalle.py +36 -22
  372. agno/tools/daytona.py +475 -0
  373. agno/tools/decorator.py +169 -14
  374. agno/tools/desi_vocal.py +23 -11
  375. agno/tools/discord.py +32 -29
  376. agno/tools/docker.py +716 -0
  377. agno/tools/duckdb.py +76 -81
  378. agno/tools/duckduckgo.py +43 -40
  379. agno/tools/e2b.py +703 -0
  380. agno/tools/eleven_labs.py +65 -54
  381. agno/tools/email.py +13 -5
  382. agno/tools/evm.py +129 -0
  383. agno/tools/exa.py +324 -42
  384. agno/tools/fal.py +39 -35
  385. agno/tools/file.py +196 -30
  386. agno/tools/file_generation.py +356 -0
  387. agno/tools/financial_datasets.py +288 -0
  388. agno/tools/firecrawl.py +108 -33
  389. agno/tools/function.py +960 -122
  390. agno/tools/giphy.py +34 -12
  391. agno/tools/github.py +1294 -97
  392. agno/tools/gmail.py +922 -0
  393. agno/tools/google_bigquery.py +117 -0
  394. agno/tools/google_drive.py +271 -0
  395. agno/tools/google_maps.py +253 -0
  396. agno/tools/googlecalendar.py +607 -107
  397. agno/tools/googlesheets.py +377 -0
  398. agno/tools/hackernews.py +20 -12
  399. agno/tools/jina.py +24 -14
  400. agno/tools/jira.py +48 -19
  401. agno/tools/knowledge.py +218 -0
  402. agno/tools/linear.py +82 -43
  403. agno/tools/linkup.py +58 -0
  404. agno/tools/local_file_system.py +15 -7
  405. agno/tools/lumalab.py +41 -26
  406. agno/tools/mcp/__init__.py +10 -0
  407. agno/tools/mcp/mcp.py +331 -0
  408. agno/tools/mcp/multi_mcp.py +347 -0
  409. agno/tools/mcp/params.py +24 -0
  410. agno/tools/mcp_toolbox.py +284 -0
  411. agno/tools/mem0.py +193 -0
  412. agno/tools/memory.py +419 -0
  413. agno/tools/mlx_transcribe.py +11 -9
  414. agno/tools/models/azure_openai.py +190 -0
  415. agno/tools/models/gemini.py +203 -0
  416. agno/tools/models/groq.py +158 -0
  417. agno/tools/models/morph.py +186 -0
  418. agno/tools/models/nebius.py +124 -0
  419. agno/tools/models_labs.py +163 -82
  420. agno/tools/moviepy_video.py +18 -13
  421. agno/tools/nano_banana.py +151 -0
  422. agno/tools/neo4j.py +134 -0
  423. agno/tools/newspaper.py +15 -4
  424. agno/tools/newspaper4k.py +19 -6
  425. agno/tools/notion.py +204 -0
  426. agno/tools/openai.py +181 -17
  427. agno/tools/openbb.py +27 -20
  428. agno/tools/opencv.py +321 -0
  429. agno/tools/openweather.py +233 -0
  430. agno/tools/oxylabs.py +385 -0
  431. agno/tools/pandas.py +25 -15
  432. agno/tools/parallel.py +314 -0
  433. agno/tools/postgres.py +238 -185
  434. agno/tools/pubmed.py +125 -13
  435. agno/tools/python.py +48 -35
  436. agno/tools/reasoning.py +283 -0
  437. agno/tools/reddit.py +207 -29
  438. agno/tools/redshift.py +406 -0
  439. agno/tools/replicate.py +69 -26
  440. agno/tools/resend.py +11 -6
  441. agno/tools/scrapegraph.py +179 -19
  442. agno/tools/searxng.py +23 -31
  443. agno/tools/serpapi.py +15 -10
  444. agno/tools/serper.py +255 -0
  445. agno/tools/shell.py +23 -12
  446. agno/tools/shopify.py +1519 -0
  447. agno/tools/slack.py +56 -14
  448. agno/tools/sleep.py +8 -6
  449. agno/tools/spider.py +35 -11
  450. agno/tools/spotify.py +919 -0
  451. agno/tools/sql.py +34 -19
  452. agno/tools/tavily.py +158 -8
  453. agno/tools/telegram.py +18 -8
  454. agno/tools/todoist.py +218 -0
  455. agno/tools/toolkit.py +134 -9
  456. agno/tools/trafilatura.py +388 -0
  457. agno/tools/trello.py +25 -28
  458. agno/tools/twilio.py +18 -9
  459. agno/tools/user_control_flow.py +78 -0
  460. agno/tools/valyu.py +228 -0
  461. agno/tools/visualization.py +467 -0
  462. agno/tools/webbrowser.py +28 -0
  463. agno/tools/webex.py +76 -0
  464. agno/tools/website.py +23 -19
  465. agno/tools/webtools.py +45 -0
  466. agno/tools/whatsapp.py +286 -0
  467. agno/tools/wikipedia.py +28 -19
  468. agno/tools/workflow.py +285 -0
  469. agno/tools/{twitter.py → x.py} +142 -46
  470. agno/tools/yfinance.py +41 -39
  471. agno/tools/youtube.py +34 -17
  472. agno/tools/zendesk.py +15 -5
  473. agno/tools/zep.py +454 -0
  474. agno/tools/zoom.py +86 -37
  475. agno/tracing/__init__.py +12 -0
  476. agno/tracing/exporter.py +157 -0
  477. agno/tracing/schemas.py +276 -0
  478. agno/tracing/setup.py +111 -0
  479. agno/utils/agent.py +938 -0
  480. agno/utils/audio.py +37 -1
  481. agno/utils/certs.py +27 -0
  482. agno/utils/code_execution.py +11 -0
  483. agno/utils/common.py +103 -20
  484. agno/utils/cryptography.py +22 -0
  485. agno/utils/dttm.py +33 -0
  486. agno/utils/events.py +700 -0
  487. agno/utils/functions.py +107 -37
  488. agno/utils/gemini.py +426 -0
  489. agno/utils/hooks.py +171 -0
  490. agno/utils/http.py +185 -0
  491. agno/utils/json_schema.py +159 -37
  492. agno/utils/knowledge.py +36 -0
  493. agno/utils/location.py +19 -0
  494. agno/utils/log.py +221 -8
  495. agno/utils/mcp.py +214 -0
  496. agno/utils/media.py +335 -14
  497. agno/utils/merge_dict.py +22 -1
  498. agno/utils/message.py +77 -2
  499. agno/utils/models/ai_foundry.py +50 -0
  500. agno/utils/models/claude.py +373 -0
  501. agno/utils/models/cohere.py +94 -0
  502. agno/utils/models/llama.py +85 -0
  503. agno/utils/models/mistral.py +100 -0
  504. agno/utils/models/openai_responses.py +140 -0
  505. agno/utils/models/schema_utils.py +153 -0
  506. agno/utils/models/watsonx.py +41 -0
  507. agno/utils/openai.py +257 -0
  508. agno/utils/pickle.py +1 -1
  509. agno/utils/pprint.py +124 -8
  510. agno/utils/print_response/agent.py +930 -0
  511. agno/utils/print_response/team.py +1914 -0
  512. agno/utils/print_response/workflow.py +1668 -0
  513. agno/utils/prompts.py +111 -0
  514. agno/utils/reasoning.py +108 -0
  515. agno/utils/response.py +163 -0
  516. agno/utils/serialize.py +32 -0
  517. agno/utils/shell.py +4 -4
  518. agno/utils/streamlit.py +487 -0
  519. agno/utils/string.py +204 -51
  520. agno/utils/team.py +139 -0
  521. agno/utils/timer.py +9 -2
  522. agno/utils/tokens.py +657 -0
  523. agno/utils/tools.py +19 -1
  524. agno/utils/whatsapp.py +305 -0
  525. agno/utils/yaml_io.py +3 -3
  526. agno/vectordb/__init__.py +2 -0
  527. agno/vectordb/base.py +87 -9
  528. agno/vectordb/cassandra/__init__.py +5 -1
  529. agno/vectordb/cassandra/cassandra.py +383 -27
  530. agno/vectordb/chroma/__init__.py +4 -0
  531. agno/vectordb/chroma/chromadb.py +748 -83
  532. agno/vectordb/clickhouse/__init__.py +7 -1
  533. agno/vectordb/clickhouse/clickhousedb.py +554 -53
  534. agno/vectordb/couchbase/__init__.py +3 -0
  535. agno/vectordb/couchbase/couchbase.py +1446 -0
  536. agno/vectordb/lancedb/__init__.py +5 -0
  537. agno/vectordb/lancedb/lance_db.py +730 -98
  538. agno/vectordb/langchaindb/__init__.py +5 -0
  539. agno/vectordb/langchaindb/langchaindb.py +163 -0
  540. agno/vectordb/lightrag/__init__.py +5 -0
  541. agno/vectordb/lightrag/lightrag.py +388 -0
  542. agno/vectordb/llamaindex/__init__.py +3 -0
  543. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  544. agno/vectordb/milvus/__init__.py +3 -0
  545. agno/vectordb/milvus/milvus.py +966 -78
  546. agno/vectordb/mongodb/__init__.py +9 -1
  547. agno/vectordb/mongodb/mongodb.py +1175 -172
  548. agno/vectordb/pgvector/__init__.py +8 -0
  549. agno/vectordb/pgvector/pgvector.py +599 -115
  550. agno/vectordb/pineconedb/__init__.py +5 -1
  551. agno/vectordb/pineconedb/pineconedb.py +406 -43
  552. agno/vectordb/qdrant/__init__.py +4 -0
  553. agno/vectordb/qdrant/qdrant.py +914 -61
  554. agno/vectordb/redis/__init__.py +9 -0
  555. agno/vectordb/redis/redisdb.py +682 -0
  556. agno/vectordb/singlestore/__init__.py +8 -1
  557. agno/vectordb/singlestore/singlestore.py +771 -0
  558. agno/vectordb/surrealdb/__init__.py +3 -0
  559. agno/vectordb/surrealdb/surrealdb.py +663 -0
  560. agno/vectordb/upstashdb/__init__.py +5 -0
  561. agno/vectordb/upstashdb/upstashdb.py +718 -0
  562. agno/vectordb/weaviate/__init__.py +8 -0
  563. agno/vectordb/weaviate/index.py +15 -0
  564. agno/vectordb/weaviate/weaviate.py +1009 -0
  565. agno/workflow/__init__.py +23 -1
  566. agno/workflow/agent.py +299 -0
  567. agno/workflow/condition.py +759 -0
  568. agno/workflow/loop.py +756 -0
  569. agno/workflow/parallel.py +853 -0
  570. agno/workflow/router.py +723 -0
  571. agno/workflow/step.py +1564 -0
  572. agno/workflow/steps.py +613 -0
  573. agno/workflow/types.py +556 -0
  574. agno/workflow/workflow.py +4327 -514
  575. agno-2.3.13.dist-info/METADATA +639 -0
  576. agno-2.3.13.dist-info/RECORD +613 -0
  577. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
  578. agno-2.3.13.dist-info/licenses/LICENSE +201 -0
  579. agno/api/playground.py +0 -91
  580. agno/api/schemas/playground.py +0 -22
  581. agno/api/schemas/user.py +0 -22
  582. agno/api/schemas/workspace.py +0 -46
  583. agno/api/user.py +0 -160
  584. agno/api/workspace.py +0 -151
  585. agno/cli/auth_server.py +0 -118
  586. agno/cli/config.py +0 -275
  587. agno/cli/console.py +0 -88
  588. agno/cli/credentials.py +0 -23
  589. agno/cli/entrypoint.py +0 -571
  590. agno/cli/operator.py +0 -355
  591. agno/cli/settings.py +0 -85
  592. agno/cli/ws/ws_cli.py +0 -817
  593. agno/constants.py +0 -13
  594. agno/document/__init__.py +0 -1
  595. agno/document/chunking/semantic.py +0 -47
  596. agno/document/chunking/strategy.py +0 -31
  597. agno/document/reader/__init__.py +0 -1
  598. agno/document/reader/arxiv_reader.py +0 -41
  599. agno/document/reader/base.py +0 -22
  600. agno/document/reader/csv_reader.py +0 -84
  601. agno/document/reader/docx_reader.py +0 -46
  602. agno/document/reader/firecrawl_reader.py +0 -99
  603. agno/document/reader/json_reader.py +0 -43
  604. agno/document/reader/pdf_reader.py +0 -219
  605. agno/document/reader/s3/pdf_reader.py +0 -46
  606. agno/document/reader/s3/text_reader.py +0 -51
  607. agno/document/reader/text_reader.py +0 -41
  608. agno/document/reader/website_reader.py +0 -175
  609. agno/document/reader/youtube_reader.py +0 -50
  610. agno/embedder/__init__.py +0 -1
  611. agno/embedder/azure_openai.py +0 -86
  612. agno/embedder/cohere.py +0 -72
  613. agno/embedder/fastembed.py +0 -37
  614. agno/embedder/google.py +0 -73
  615. agno/embedder/huggingface.py +0 -54
  616. agno/embedder/mistral.py +0 -80
  617. agno/embedder/ollama.py +0 -57
  618. agno/embedder/openai.py +0 -74
  619. agno/embedder/sentence_transformer.py +0 -38
  620. agno/embedder/voyageai.py +0 -64
  621. agno/eval/perf.py +0 -201
  622. agno/file/__init__.py +0 -1
  623. agno/file/file.py +0 -16
  624. agno/file/local/csv.py +0 -32
  625. agno/file/local/txt.py +0 -19
  626. agno/infra/app.py +0 -240
  627. agno/infra/base.py +0 -144
  628. agno/infra/context.py +0 -20
  629. agno/infra/db_app.py +0 -52
  630. agno/infra/resource.py +0 -205
  631. agno/infra/resources.py +0 -55
  632. agno/knowledge/agent.py +0 -230
  633. agno/knowledge/arxiv.py +0 -22
  634. agno/knowledge/combined.py +0 -22
  635. agno/knowledge/csv.py +0 -28
  636. agno/knowledge/csv_url.py +0 -19
  637. agno/knowledge/document.py +0 -20
  638. agno/knowledge/docx.py +0 -30
  639. agno/knowledge/json.py +0 -28
  640. agno/knowledge/langchain.py +0 -71
  641. agno/knowledge/llamaindex.py +0 -66
  642. agno/knowledge/pdf.py +0 -28
  643. agno/knowledge/pdf_url.py +0 -26
  644. agno/knowledge/s3/base.py +0 -60
  645. agno/knowledge/s3/pdf.py +0 -21
  646. agno/knowledge/s3/text.py +0 -23
  647. agno/knowledge/text.py +0 -30
  648. agno/knowledge/website.py +0 -88
  649. agno/knowledge/wikipedia.py +0 -31
  650. agno/knowledge/youtube.py +0 -22
  651. agno/memory/agent.py +0 -392
  652. agno/memory/classifier.py +0 -104
  653. agno/memory/db/__init__.py +0 -1
  654. agno/memory/db/base.py +0 -42
  655. agno/memory/db/mongodb.py +0 -189
  656. agno/memory/db/postgres.py +0 -203
  657. agno/memory/db/sqlite.py +0 -193
  658. agno/memory/memory.py +0 -15
  659. agno/memory/row.py +0 -36
  660. agno/memory/summarizer.py +0 -192
  661. agno/memory/summary.py +0 -19
  662. agno/memory/workflow.py +0 -38
  663. agno/models/google/gemini_openai.py +0 -26
  664. agno/models/ollama/hermes.py +0 -221
  665. agno/models/ollama/tools.py +0 -362
  666. agno/models/vertexai/gemini.py +0 -595
  667. agno/playground/__init__.py +0 -3
  668. agno/playground/async_router.py +0 -421
  669. agno/playground/deploy.py +0 -249
  670. agno/playground/operator.py +0 -92
  671. agno/playground/playground.py +0 -91
  672. agno/playground/schemas.py +0 -76
  673. agno/playground/serve.py +0 -55
  674. agno/playground/sync_router.py +0 -405
  675. agno/reasoning/agent.py +0 -68
  676. agno/run/response.py +0 -112
  677. agno/storage/agent/__init__.py +0 -0
  678. agno/storage/agent/base.py +0 -38
  679. agno/storage/agent/dynamodb.py +0 -350
  680. agno/storage/agent/json.py +0 -92
  681. agno/storage/agent/mongodb.py +0 -228
  682. agno/storage/agent/postgres.py +0 -367
  683. agno/storage/agent/session.py +0 -79
  684. agno/storage/agent/singlestore.py +0 -303
  685. agno/storage/agent/sqlite.py +0 -357
  686. agno/storage/agent/yaml.py +0 -93
  687. agno/storage/workflow/__init__.py +0 -0
  688. agno/storage/workflow/base.py +0 -40
  689. agno/storage/workflow/mongodb.py +0 -233
  690. agno/storage/workflow/postgres.py +0 -366
  691. agno/storage/workflow/session.py +0 -60
  692. agno/storage/workflow/sqlite.py +0 -359
  693. agno/tools/googlesearch.py +0 -88
  694. agno/utils/defaults.py +0 -57
  695. agno/utils/filesystem.py +0 -39
  696. agno/utils/git.py +0 -52
  697. agno/utils/json_io.py +0 -30
  698. agno/utils/load_env.py +0 -19
  699. agno/utils/py_io.py +0 -19
  700. agno/utils/pyproject.py +0 -18
  701. agno/utils/resource_filter.py +0 -31
  702. agno/vectordb/singlestore/s2vectordb.py +0 -390
  703. agno/vectordb/singlestore/s2vectordb2.py +0 -355
  704. agno/workspace/__init__.py +0 -0
  705. agno/workspace/config.py +0 -325
  706. agno/workspace/enums.py +0 -6
  707. agno/workspace/helpers.py +0 -48
  708. agno/workspace/operator.py +0 -758
  709. agno/workspace/settings.py +0 -63
  710. agno-0.1.2.dist-info/LICENSE +0 -375
  711. agno-0.1.2.dist-info/METADATA +0 -502
  712. agno-0.1.2.dist-info/RECORD +0 -352
  713. agno-0.1.2.dist-info/entry_points.txt +0 -3
  714. /agno/{cli → db/migrations}/__init__.py +0 -0
  715. /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
  716. /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
  717. /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
  718. /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
  719. /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
  720. /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
  721. /agno/{reranker → utils/models}/__init__.py +0 -0
  722. /agno/{storage → utils/print_response}/__init__.py +0 -0
  723. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,489 @@
1
+ from collections.abc import AsyncIterator
2
+ from dataclasses import dataclass
3
+ from os import getenv
4
+ from typing import Any, Dict, Iterator, List, Optional, Type, Union
5
+
6
+ import httpx
7
+ from pydantic import BaseModel
8
+
9
+ from agno.exceptions import ModelProviderError
10
+ from agno.models.base import Model
11
+ from agno.models.message import Message
12
+ from agno.models.metrics import Metrics
13
+ from agno.models.response import ModelResponse
14
+ from agno.run.agent import RunOutput
15
+ from agno.utils.log import log_debug, log_error
16
+ from agno.utils.models.ai_foundry import format_message
17
+
18
+ try:
19
+ from azure.ai.inference import ChatCompletionsClient
20
+ from azure.ai.inference.aio import ChatCompletionsClient as AsyncChatCompletionsClient
21
+ from azure.ai.inference.models import (
22
+ ChatCompletions,
23
+ ChatCompletionsToolDefinition,
24
+ FunctionDefinition,
25
+ JsonSchemaFormat,
26
+ StreamingChatCompletionsUpdate,
27
+ StreamingChatResponseToolCallUpdate,
28
+ )
29
+ from azure.core.credentials import AzureKeyCredential
30
+ from azure.core.exceptions import HttpResponseError
31
+ except ImportError:
32
+ raise ImportError(
33
+ "`azure-ai-inference` not installed. Please install it via `pip install azure-ai-inference aiohttp`."
34
+ )
35
+
36
+
37
+ @dataclass
38
+ class AzureAIFoundry(Model):
39
+ """
40
+ A class for interacting with Azure AI Interface models.
41
+
42
+ - For Managed Compute, set the `api_key` to your Azure AI Foundry API key and the `azure_endpoint` to the endpoint URL in the format `https://<your-host-name>.<your-azure-region>.models.ai.azure.com/models`
43
+ - For Serverless API, set the `api_key` to your Azure AI Foundry API key and the `azure_endpoint` to the endpoint URL in the format `https://<your-host-name>.<your-azure-region>.models.ai.azure.com/models`
44
+ - For Github Models, set the `api_key` to the Github Personal Access Token.
45
+ - For Azure OpenAI, set the `api_key` to your Azure AI Foundry API key, the `api_version` to `2024-06-01` and the `azure_endpoint` to the endpoint URL in the format `https://<your-resource-name>.openai.azure.com/openai/deployments/<your-deployment-name>`
46
+
47
+ For more information, see: https://learn.microsoft.com/en-gb/python/api/overview/azure/ai-inference-readme
48
+ """
49
+
50
+ id: str = "gpt-4o"
51
+ name: str = "AzureAIFoundry"
52
+ provider: str = "Azure"
53
+
54
+ # Request parameters
55
+ temperature: Optional[float] = None
56
+ max_tokens: Optional[int] = None
57
+ frequency_penalty: Optional[float] = None
58
+ presence_penalty: Optional[float] = None
59
+ top_p: Optional[float] = None
60
+ stop: Optional[Union[str, List[str]]] = None
61
+ seed: Optional[int] = None
62
+ model_extras: Optional[Dict[str, Any]] = None
63
+ strict_output: bool = True # When True, guarantees schema adherence for structured outputs. When False, attempts to follow schema as a guide but may occasionally deviate
64
+ request_params: Optional[Dict[str, Any]] = None
65
+ # Client parameters
66
+ api_key: Optional[str] = None
67
+ api_version: Optional[str] = None
68
+ azure_endpoint: Optional[str] = None
69
+ timeout: Optional[float] = None
70
+ max_retries: Optional[int] = None
71
+ http_client: Optional[httpx.Client] = None
72
+ client_params: Optional[Dict[str, Any]] = None
73
+
74
+ # Azure AI clients
75
+ client: Optional[ChatCompletionsClient] = None
76
+ async_client: Optional[AsyncChatCompletionsClient] = None
77
+
78
+ def get_request_params(
79
+ self,
80
+ tools: Optional[List[Dict[str, Any]]] = None,
81
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
82
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
83
+ ) -> Dict[str, Any]:
84
+ """Get the parameters for creating an Azure AI request."""
85
+ base_params = {
86
+ "temperature": self.temperature,
87
+ "max_tokens": self.max_tokens,
88
+ "frequency_penalty": self.frequency_penalty,
89
+ "presence_penalty": self.presence_penalty,
90
+ "top_p": self.top_p,
91
+ "stop": self.stop,
92
+ "seed": self.seed,
93
+ "model": self.id,
94
+ "model_extras": self.model_extras,
95
+ }
96
+
97
+ if tools:
98
+ parsed_tools = []
99
+ for _tool in tools:
100
+ parsed_tools.append(
101
+ ChatCompletionsToolDefinition(
102
+ function=FunctionDefinition(
103
+ name=_tool["function"]["name"],
104
+ description=_tool["function"]["description"],
105
+ parameters=_tool["function"]["parameters"],
106
+ )
107
+ )
108
+ )
109
+ base_params["tools"] = parsed_tools # type: ignore
110
+ if tool_choice:
111
+ base_params["tool_choice"] = tool_choice
112
+
113
+ if response_format is not None:
114
+ if isinstance(response_format, type) and issubclass(response_format, BaseModel):
115
+ base_params["response_format"] = ( # type: ignore
116
+ JsonSchemaFormat(
117
+ name=response_format.__name__,
118
+ schema=response_format.model_json_schema(), # type: ignore
119
+ description=response_format.__doc__,
120
+ strict=self.strict_output,
121
+ ),
122
+ )
123
+
124
+ request_params = {k: v for k, v in base_params.items() if v is not None}
125
+ if self.request_params:
126
+ request_params.update(self.request_params)
127
+
128
+ if request_params:
129
+ log_debug(f"Calling {self.provider} with request parameters: {request_params}", log_level=2)
130
+ return request_params
131
+
132
+ def _get_client_params(self) -> Dict[str, Any]:
133
+ """Get the parameters for creating an Azure AI client."""
134
+ self.api_key = self.api_key or getenv("AZURE_API_KEY")
135
+ self.api_version = self.api_version or getenv("AZURE_API_VERSION", "2024-05-01-preview")
136
+ self.azure_endpoint = self.azure_endpoint or getenv("AZURE_ENDPOINT")
137
+
138
+ if not self.api_key:
139
+ log_error("AZURE_API_KEY not set. Please set the AZURE_API_KEY environment variable.")
140
+ if not self.azure_endpoint:
141
+ log_error("AZURE_ENDPOINT not set. Please set the AZURE_ENDPOINT environment variable.")
142
+
143
+ base_params = {
144
+ "endpoint": self.azure_endpoint,
145
+ "credential": AzureKeyCredential(self.api_key),
146
+ "api_version": self.api_version,
147
+ }
148
+
149
+ # Create client_params dict with non-None values
150
+ client_params = {k: v for k, v in base_params.items() if v is not None}
151
+ # Add additional client params if provided
152
+ if self.client_params:
153
+ client_params.update(self.client_params)
154
+
155
+ return client_params
156
+
157
+ def get_client(self) -> ChatCompletionsClient:
158
+ """
159
+ Returns an Azure AI client.
160
+
161
+ Returns:
162
+ ChatCompletionsClient: An instance of the Azure AI client.
163
+ """
164
+ # Check if client exists and is not closed
165
+ # Azure's client doesn't have is_closed(), so we check if _client exists
166
+ if self.client and hasattr(self.client, "_client"):
167
+ return self.client
168
+
169
+ client_params = self._get_client_params()
170
+ self.client = ChatCompletionsClient(**client_params)
171
+ return self.client
172
+
173
+ def get_async_client(self) -> AsyncChatCompletionsClient:
174
+ """
175
+ Returns an asynchronous Azure AI client.
176
+
177
+ Returns:
178
+ AsyncChatCompletionsClient: An instance of the asynchronous Azure AI client.
179
+ """
180
+ # Check if client exists and is not closed
181
+ # Azure's async client doesn't have is_closed(), so we check if _client exists
182
+ if self.async_client and hasattr(self.async_client, "_client"):
183
+ return self.async_client
184
+
185
+ client_params = self._get_client_params()
186
+
187
+ self.async_client = AsyncChatCompletionsClient(**client_params)
188
+ return self.async_client
189
+
190
+ def close(self) -> None:
191
+ """Close the synchronous client and clean up resources."""
192
+ if self.client:
193
+ self.client.close()
194
+ self.client = None
195
+
196
+ async def aclose(self) -> None:
197
+ """Close the asynchronous client and clean up resources."""
198
+ if self.async_client:
199
+ await self.async_client.close()
200
+ self.async_client = None
201
+
202
+ def invoke(
203
+ self,
204
+ messages: List[Message],
205
+ assistant_message: Message,
206
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
207
+ tools: Optional[List[Dict[str, Any]]] = None,
208
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
209
+ run_response: Optional[RunOutput] = None,
210
+ compress_tool_results: bool = False,
211
+ ) -> ModelResponse:
212
+ """
213
+ Send a chat completion request to the Azure AI API.
214
+ """
215
+ try:
216
+ if run_response and run_response.metrics:
217
+ run_response.metrics.set_time_to_first_token()
218
+
219
+ assistant_message.metrics.start_timer()
220
+ provider_response = self.get_client().complete(
221
+ messages=[format_message(m, compress_tool_results) for m in messages],
222
+ **self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
223
+ )
224
+ assistant_message.metrics.stop_timer()
225
+
226
+ model_response = self._parse_provider_response(provider_response, response_format=response_format)
227
+
228
+ return model_response
229
+
230
+ except HttpResponseError as e:
231
+ log_error(f"Azure AI API error: {e}")
232
+ raise ModelProviderError(
233
+ message=e.reason or "Azure AI API error",
234
+ status_code=e.status_code or 502,
235
+ model_name=self.name,
236
+ model_id=self.id,
237
+ ) from e
238
+ except Exception as e:
239
+ log_error(f"Error from Azure AI API: {e}")
240
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
241
+
242
+ async def ainvoke(
243
+ self,
244
+ messages: List[Message],
245
+ assistant_message: Message,
246
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
247
+ tools: Optional[List[Dict[str, Any]]] = None,
248
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
249
+ run_response: Optional[RunOutput] = None,
250
+ compress_tool_results: bool = False,
251
+ ) -> ModelResponse:
252
+ """
253
+ Sends an asynchronous chat completion request to the Azure AI API.
254
+ """
255
+
256
+ try:
257
+ if run_response and run_response.metrics:
258
+ run_response.metrics.set_time_to_first_token()
259
+
260
+ assistant_message.metrics.start_timer()
261
+ provider_response = await self.get_async_client().complete(
262
+ messages=[format_message(m, compress_tool_results) for m in messages],
263
+ **self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
264
+ )
265
+ assistant_message.metrics.stop_timer()
266
+
267
+ model_response = self._parse_provider_response(provider_response, response_format=response_format) # type: ignore
268
+
269
+ return model_response
270
+
271
+ except HttpResponseError as e:
272
+ log_error(f"Azure AI API error: {e}")
273
+ raise ModelProviderError(
274
+ message=e.reason or "Azure AI API error",
275
+ status_code=e.status_code or 502,
276
+ model_name=self.name,
277
+ model_id=self.id,
278
+ ) from e
279
+ except Exception as e:
280
+ log_error(f"Error from Azure AI API: {e}")
281
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
282
+
283
+ def invoke_stream(
284
+ self,
285
+ messages: List[Message],
286
+ assistant_message: Message,
287
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
288
+ tools: Optional[List[Dict[str, Any]]] = None,
289
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
290
+ run_response: Optional[RunOutput] = None,
291
+ compress_tool_results: bool = False,
292
+ ) -> Iterator[ModelResponse]:
293
+ """
294
+ Send a streaming chat completion request to the Azure AI API.
295
+ """
296
+ try:
297
+ if run_response and run_response.metrics:
298
+ run_response.metrics.set_time_to_first_token()
299
+
300
+ assistant_message.metrics.start_timer()
301
+
302
+ for chunk in self.get_client().complete(
303
+ messages=[format_message(m, compress_tool_results) for m in messages],
304
+ stream=True,
305
+ **self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
306
+ ):
307
+ yield self._parse_provider_response_delta(chunk)
308
+
309
+ assistant_message.metrics.stop_timer()
310
+
311
+ except HttpResponseError as e:
312
+ log_error(f"Azure AI API error: {e}")
313
+ raise ModelProviderError(
314
+ message=e.reason or "Azure AI API error",
315
+ status_code=e.status_code or 502,
316
+ model_name=self.name,
317
+ model_id=self.id,
318
+ ) from e
319
+ except Exception as e:
320
+ log_error(f"Error from Azure AI API: {e}")
321
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
322
+
323
+ async def ainvoke_stream(
324
+ self,
325
+ messages: List[Message],
326
+ assistant_message: Message,
327
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
328
+ tools: Optional[List[Dict[str, Any]]] = None,
329
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
330
+ run_response: Optional[RunOutput] = None,
331
+ compress_tool_results: bool = False,
332
+ ) -> AsyncIterator[ModelResponse]:
333
+ """
334
+ Sends an asynchronous streaming chat completion request to the Azure AI API.
335
+ """
336
+ try:
337
+ if run_response and run_response.metrics:
338
+ run_response.metrics.set_time_to_first_token()
339
+
340
+ assistant_message.metrics.start_timer()
341
+
342
+ async_stream = await self.get_async_client().complete(
343
+ messages=[format_message(m, compress_tool_results) for m in messages],
344
+ stream=True,
345
+ **self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
346
+ )
347
+ async for chunk in async_stream: # type: ignore
348
+ yield self._parse_provider_response_delta(chunk)
349
+
350
+ assistant_message.metrics.stop_timer()
351
+
352
+ except HttpResponseError as e:
353
+ log_error(f"Azure AI API error: {e}")
354
+ raise ModelProviderError(
355
+ message=e.reason or "Azure AI API error",
356
+ status_code=e.status_code or 502,
357
+ model_name=self.name,
358
+ model_id=self.id,
359
+ ) from e
360
+ except Exception as e:
361
+ log_error(f"Error from Azure AI API: {e}")
362
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
363
+
364
+ def _parse_provider_response(self, response: ChatCompletions, **kwargs) -> ModelResponse:
365
+ """
366
+ Parse the Azure AI response into a ModelResponse.
367
+
368
+ Args:
369
+ response: Raw response from Azure AI
370
+
371
+ Returns:
372
+ ModelResponse: Parsed response data
373
+ """
374
+ model_response = ModelResponse()
375
+
376
+ try:
377
+ # Get the first choice from the response
378
+ choice = response.choices[0]
379
+
380
+ # Add content
381
+ if choice.message.content is not None:
382
+ model_response.content = choice.message.content
383
+
384
+ # Add role
385
+ if choice.message.role is not None:
386
+ model_response.role = choice.message.role
387
+
388
+ # Add tool calls if present
389
+ if choice.message.tool_calls and len(choice.message.tool_calls) > 0:
390
+ model_response.tool_calls = [
391
+ {
392
+ "id": t.id,
393
+ "type": t.type,
394
+ "function": {
395
+ "name": t.function.name,
396
+ "arguments": t.function.arguments,
397
+ },
398
+ }
399
+ for t in choice.message.tool_calls
400
+ ]
401
+
402
+ # Add usage metrics if present
403
+ if response.usage is not None:
404
+ model_response.response_usage = self._get_metrics(response.usage)
405
+
406
+ except Exception as e:
407
+ log_error(f"Error parsing Azure AI response: {e}")
408
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
409
+
410
+ return model_response
411
+
412
+ # Override base method
413
+ @staticmethod
414
+ def parse_tool_calls(tool_calls_data: List[StreamingChatResponseToolCallUpdate]) -> List[Dict[str, Any]]:
415
+ """
416
+ Build tool calls from streamed tool call data.
417
+
418
+ Args:
419
+ tool_calls_data (List[StreamingChatResponseToolCallUpdate]): The tool call data to build from.
420
+
421
+ Returns:
422
+ List[Dict[str, Any]]: The built tool calls.
423
+ """
424
+ tool_calls: List[Dict[str, Any]] = []
425
+
426
+ current_tool_call: Dict[str, Any] = {}
427
+ for tool_call in tool_calls_data:
428
+ if tool_call.id: # New tool call starts
429
+ if current_tool_call: # Store previous tool call if exists
430
+ tool_calls.append(current_tool_call)
431
+ current_tool_call = {
432
+ "id": tool_call.id,
433
+ "type": "function",
434
+ "function": {"name": tool_call.function.name, "arguments": tool_call.function.arguments or ""},
435
+ }
436
+ elif current_tool_call and tool_call.function and tool_call.function.arguments:
437
+ # Append arguments to current tool call
438
+ current_tool_call["function"]["arguments"] += tool_call.function.arguments
439
+
440
+ if current_tool_call: # Append final tool call
441
+ tool_calls.append(current_tool_call)
442
+
443
+ return tool_calls
444
+
445
+ def _parse_provider_response_delta(self, response_delta: StreamingChatCompletionsUpdate) -> ModelResponse:
446
+ """
447
+ Parse the Azure AI streaming response into ModelResponse objects.
448
+
449
+ Args:
450
+ response_delta: Raw response chunk from Azure AI
451
+
452
+ Returns:
453
+ ModelResponse: Parsed response data
454
+ """
455
+ model_response = ModelResponse()
456
+
457
+ try:
458
+ if response_delta.choices and len(response_delta.choices) > 0:
459
+ choice_delta = response_delta.choices[0].delta
460
+
461
+ if choice_delta:
462
+ # Add content
463
+ if choice_delta.content is not None:
464
+ model_response.content = choice_delta.content
465
+
466
+ # Add tool calls if present
467
+ if choice_delta.tool_calls and len(choice_delta.tool_calls) > 0:
468
+ model_response.tool_calls = choice_delta.tool_calls # type: ignore
469
+ # Add usage metrics if present
470
+ if response_delta.usage is not None:
471
+ model_response.response_usage = self._get_metrics(response_delta.usage)
472
+
473
+ except Exception as e:
474
+ log_error(f"Error parsing Azure AI response delta: {e}")
475
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
476
+
477
+ return model_response
478
+
479
+ def _get_metrics(self, response_usage) -> Metrics:
480
+ """
481
+ Parse the given Azure AI Foundry usage into an Agno Metrics object.
482
+ """
483
+ metrics = Metrics()
484
+
485
+ metrics.input_tokens = response_usage.get("prompt_tokens", 0)
486
+ metrics.output_tokens = response_usage.get("completion_tokens", 0)
487
+ metrics.total_tokens = metrics.input_tokens + metrics.output_tokens
488
+
489
+ return metrics
@@ -4,13 +4,16 @@ from typing import Any, Dict, Optional
4
4
 
5
5
  import httpx
6
6
 
7
+ from agno.exceptions import ModelAuthenticationError
7
8
  from agno.models.openai.like import OpenAILike
9
+ from agno.utils.http import get_default_async_client, get_default_sync_client
10
+ from agno.utils.log import log_warning
8
11
 
9
12
  try:
10
13
  from openai import AsyncAzureOpenAI as AsyncAzureOpenAIClient
11
14
  from openai import AzureOpenAI as AzureOpenAIClient
12
- except (ModuleNotFoundError, ImportError):
13
- raise ImportError("`azure openai` not installed. Please install using `pip install openai`")
15
+ except ImportError:
16
+ raise ImportError("`openai` not installed. Please install using `pip install openai`")
14
17
 
15
18
 
16
19
  @dataclass
@@ -31,20 +34,68 @@ class AzureOpenAI(OpenAILike):
31
34
  azure_ad_token (Optional[str]): The Azure AD token to use.
32
35
  azure_ad_token_provider (Optional[Any]): The Azure AD token provider to use.
33
36
  organization (Optional[str]): The organization to use.
34
- openai_client (Optional[AzureOpenAIClient]): The OpenAI client to use.
37
+ client (Optional[AzureOpenAIClient]): The OpenAI client to use.
38
+ async_client (Optional[AsyncAzureOpenAIClient]): The OpenAI client to use.
35
39
  """
36
40
 
37
41
  id: str
38
42
  name: str = "AzureOpenAI"
39
43
  provider: str = "Azure"
40
44
 
41
- api_key: Optional[str] = getenv("AZURE_OPENAI_API_KEY")
42
- api_version: str = getenv("AZURE_OPENAI_API_VERSION", "2024-10-21")
43
- azure_endpoint: Optional[str] = getenv("AZURE_OPENAI_ENDPOINT")
44
- azure_deployment: Optional[str] = getenv("AZURE_DEPLOYMENT")
45
+ supports_native_structured_outputs: bool = True
46
+
47
+ api_key: Optional[str] = None
48
+ api_version: Optional[str] = "2024-10-21"
49
+ azure_endpoint: Optional[str] = None
50
+ azure_deployment: Optional[str] = None
51
+ base_url: Optional[str] = None
45
52
  azure_ad_token: Optional[str] = None
46
53
  azure_ad_token_provider: Optional[Any] = None
47
- openai_client: Optional[AzureOpenAIClient] = None
54
+
55
+ default_headers: Optional[Dict[str, str]] = None
56
+ default_query: Optional[Dict[str, Any]] = None
57
+
58
+ client: Optional[AzureOpenAIClient] = None
59
+ async_client: Optional[AsyncAzureOpenAIClient] = None
60
+
61
+ def _get_client_params(self) -> Dict[str, Any]:
62
+ _client_params: Dict[str, Any] = {}
63
+
64
+ self.api_key = self.api_key or getenv("AZURE_OPENAI_API_KEY")
65
+ self.azure_endpoint = self.azure_endpoint or getenv("AZURE_OPENAI_ENDPOINT")
66
+ self.azure_deployment = self.azure_deployment or getenv("AZURE_OPENAI_DEPLOYMENT")
67
+
68
+ if not (self.api_key or self.azure_ad_token):
69
+ if not self.api_key:
70
+ raise ModelAuthenticationError(
71
+ message="AZURE_OPENAI_API_KEY not set. Please set the AZURE_OPENAI_API_KEY environment variable.",
72
+ model_name=self.name,
73
+ )
74
+ if not self.azure_ad_token:
75
+ raise ModelAuthenticationError(
76
+ message="AZURE_AD_TOKEN not set. Please set the AZURE_AD_TOKEN environment variable.",
77
+ model_name=self.name,
78
+ )
79
+
80
+ params_mapping = {
81
+ "api_key": self.api_key,
82
+ "api_version": self.api_version,
83
+ "organization": self.organization,
84
+ "azure_endpoint": self.azure_endpoint,
85
+ "azure_deployment": self.azure_deployment,
86
+ "base_url": self.base_url,
87
+ "azure_ad_token": self.azure_ad_token,
88
+ "azure_ad_token_provider": self.azure_ad_token_provider,
89
+ }
90
+ if self.default_headers is not None:
91
+ _client_params["default_headers"] = self.default_headers
92
+ if self.default_query is not None:
93
+ _client_params["default_query"] = self.default_query
94
+
95
+ _client_params.update({k: v for k, v in params_mapping.items() if v is not None})
96
+ if self.client_params:
97
+ _client_params.update(self.client_params)
98
+ return _client_params
48
99
 
49
100
  def get_client(self) -> AzureOpenAIClient:
50
101
  """
@@ -54,12 +105,25 @@ class AzureOpenAI(OpenAILike):
54
105
  AzureOpenAIClient: The OpenAI client.
55
106
 
56
107
  """
57
- if self.openai_client:
58
- return self.openai_client
108
+ if self.client is not None and not self.client.is_closed():
109
+ return self.client
59
110
 
60
111
  _client_params: Dict[str, Any] = self._get_client_params()
61
112
 
62
- return AzureOpenAIClient(**_client_params)
113
+ if self.http_client:
114
+ if isinstance(self.http_client, httpx.Client):
115
+ _client_params["http_client"] = self.http_client
116
+ else:
117
+ log_warning("http_client is not an instance of httpx.Client. Using default global httpx.Client.")
118
+ # Use global sync client when user http_client is invalid
119
+ _client_params["http_client"] = get_default_sync_client()
120
+ else:
121
+ # Use global sync client when no custom http_client is provided
122
+ _client_params["http_client"] = get_default_sync_client()
123
+
124
+ # Create client
125
+ self.client = AzureOpenAIClient(**_client_params)
126
+ return self.client
63
127
 
64
128
  def get_async_client(self) -> AsyncAzureOpenAIClient:
65
129
  """
@@ -68,38 +132,23 @@ class AzureOpenAI(OpenAILike):
68
132
  Returns:
69
133
  AsyncAzureOpenAIClient: An instance of the asynchronous OpenAI client.
70
134
  """
135
+ if self.async_client and not self.async_client.is_closed():
136
+ return self.async_client
71
137
 
72
138
  _client_params: Dict[str, Any] = self._get_client_params()
73
139
 
74
140
  if self.http_client:
75
- _client_params["http_client"] = self.http_client
141
+ if isinstance(self.http_client, httpx.AsyncClient):
142
+ _client_params["http_client"] = self.http_client
143
+ else:
144
+ log_warning(
145
+ "http_client is not an instance of httpx.AsyncClient. Using default global httpx.AsyncClient."
146
+ )
147
+ # Use global async client when user http_client is invalid
148
+ _client_params["http_client"] = get_default_async_client()
76
149
  else:
77
- # Create a new async HTTP client with custom limits
78
- _client_params["http_client"] = httpx.AsyncClient(
79
- limits=httpx.Limits(max_connections=1000, max_keepalive_connections=100)
80
- )
81
- return AsyncAzureOpenAIClient(**_client_params)
150
+ # Use global async client when no custom http_client is provided
151
+ _client_params["http_client"] = get_default_async_client()
82
152
 
83
- def _get_client_params(self) -> Dict[str, Any]:
84
- _client_params: Dict[str, Any] = {}
85
- if self.api_key:
86
- _client_params["api_key"] = self.api_key
87
- if self.api_version:
88
- _client_params["api_version"] = self.api_version
89
- if self.organization:
90
- _client_params["organization"] = self.organization
91
- if self.azure_endpoint:
92
- _client_params["azure_endpoint"] = self.azure_endpoint
93
- if self.azure_deployment:
94
- _client_params["azure_deployment"] = self.azure_deployment
95
- if self.base_url:
96
- _client_params["base_url"] = self.base_url
97
- if self.azure_ad_token:
98
- _client_params["azure_ad_token"] = self.azure_ad_token
99
- if self.azure_ad_token_provider:
100
- _client_params["azure_ad_token_provider"] = self.azure_ad_token_provider
101
- if self.http_client:
102
- _client_params["http_client"] = self.http_client
103
- if self.client_params:
104
- _client_params.update(self.client_params)
105
- return _client_params
153
+ self.async_client = AsyncAzureOpenAIClient(**_client_params)
154
+ return self.async_client