agno 2.2.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (575) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +51 -0
  3. agno/agent/agent.py +10405 -0
  4. agno/api/__init__.py +0 -0
  5. agno/api/agent.py +28 -0
  6. agno/api/api.py +40 -0
  7. agno/api/evals.py +22 -0
  8. agno/api/os.py +17 -0
  9. agno/api/routes.py +13 -0
  10. agno/api/schemas/__init__.py +9 -0
  11. agno/api/schemas/agent.py +16 -0
  12. agno/api/schemas/evals.py +16 -0
  13. agno/api/schemas/os.py +14 -0
  14. agno/api/schemas/response.py +6 -0
  15. agno/api/schemas/team.py +16 -0
  16. agno/api/schemas/utils.py +21 -0
  17. agno/api/schemas/workflows.py +16 -0
  18. agno/api/settings.py +53 -0
  19. agno/api/team.py +30 -0
  20. agno/api/workflow.py +28 -0
  21. agno/cloud/aws/base.py +214 -0
  22. agno/cloud/aws/s3/__init__.py +2 -0
  23. agno/cloud/aws/s3/api_client.py +43 -0
  24. agno/cloud/aws/s3/bucket.py +195 -0
  25. agno/cloud/aws/s3/object.py +57 -0
  26. agno/culture/__init__.py +3 -0
  27. agno/culture/manager.py +956 -0
  28. agno/db/__init__.py +24 -0
  29. agno/db/async_postgres/__init__.py +3 -0
  30. agno/db/base.py +598 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2042 -0
  33. agno/db/dynamo/schemas.py +314 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +1795 -0
  37. agno/db/firestore/schemas.py +140 -0
  38. agno/db/firestore/utils.py +376 -0
  39. agno/db/gcs_json/__init__.py +3 -0
  40. agno/db/gcs_json/gcs_json_db.py +1335 -0
  41. agno/db/gcs_json/utils.py +228 -0
  42. agno/db/in_memory/__init__.py +3 -0
  43. agno/db/in_memory/in_memory_db.py +1160 -0
  44. agno/db/in_memory/utils.py +230 -0
  45. agno/db/json/__init__.py +3 -0
  46. agno/db/json/json_db.py +1328 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/__init__.py +0 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/mongo/__init__.py +17 -0
  51. agno/db/mongo/async_mongo.py +2026 -0
  52. agno/db/mongo/mongo.py +1982 -0
  53. agno/db/mongo/schemas.py +87 -0
  54. agno/db/mongo/utils.py +259 -0
  55. agno/db/mysql/__init__.py +3 -0
  56. agno/db/mysql/mysql.py +2308 -0
  57. agno/db/mysql/schemas.py +138 -0
  58. agno/db/mysql/utils.py +355 -0
  59. agno/db/postgres/__init__.py +4 -0
  60. agno/db/postgres/async_postgres.py +1927 -0
  61. agno/db/postgres/postgres.py +2260 -0
  62. agno/db/postgres/schemas.py +139 -0
  63. agno/db/postgres/utils.py +442 -0
  64. agno/db/redis/__init__.py +3 -0
  65. agno/db/redis/redis.py +1660 -0
  66. agno/db/redis/schemas.py +123 -0
  67. agno/db/redis/utils.py +346 -0
  68. agno/db/schemas/__init__.py +4 -0
  69. agno/db/schemas/culture.py +120 -0
  70. agno/db/schemas/evals.py +33 -0
  71. agno/db/schemas/knowledge.py +40 -0
  72. agno/db/schemas/memory.py +46 -0
  73. agno/db/schemas/metrics.py +0 -0
  74. agno/db/singlestore/__init__.py +3 -0
  75. agno/db/singlestore/schemas.py +130 -0
  76. agno/db/singlestore/singlestore.py +2272 -0
  77. agno/db/singlestore/utils.py +384 -0
  78. agno/db/sqlite/__init__.py +4 -0
  79. agno/db/sqlite/async_sqlite.py +2293 -0
  80. agno/db/sqlite/schemas.py +133 -0
  81. agno/db/sqlite/sqlite.py +2288 -0
  82. agno/db/sqlite/utils.py +431 -0
  83. agno/db/surrealdb/__init__.py +3 -0
  84. agno/db/surrealdb/metrics.py +292 -0
  85. agno/db/surrealdb/models.py +309 -0
  86. agno/db/surrealdb/queries.py +71 -0
  87. agno/db/surrealdb/surrealdb.py +1353 -0
  88. agno/db/surrealdb/utils.py +147 -0
  89. agno/db/utils.py +116 -0
  90. agno/debug.py +18 -0
  91. agno/eval/__init__.py +14 -0
  92. agno/eval/accuracy.py +834 -0
  93. agno/eval/performance.py +773 -0
  94. agno/eval/reliability.py +306 -0
  95. agno/eval/utils.py +119 -0
  96. agno/exceptions.py +161 -0
  97. agno/filters.py +354 -0
  98. agno/guardrails/__init__.py +6 -0
  99. agno/guardrails/base.py +19 -0
  100. agno/guardrails/openai.py +144 -0
  101. agno/guardrails/pii.py +94 -0
  102. agno/guardrails/prompt_injection.py +52 -0
  103. agno/integrations/__init__.py +0 -0
  104. agno/integrations/discord/__init__.py +3 -0
  105. agno/integrations/discord/client.py +203 -0
  106. agno/knowledge/__init__.py +5 -0
  107. agno/knowledge/chunking/__init__.py +0 -0
  108. agno/knowledge/chunking/agentic.py +79 -0
  109. agno/knowledge/chunking/document.py +91 -0
  110. agno/knowledge/chunking/fixed.py +57 -0
  111. agno/knowledge/chunking/markdown.py +151 -0
  112. agno/knowledge/chunking/recursive.py +63 -0
  113. agno/knowledge/chunking/row.py +39 -0
  114. agno/knowledge/chunking/semantic.py +86 -0
  115. agno/knowledge/chunking/strategy.py +165 -0
  116. agno/knowledge/content.py +74 -0
  117. agno/knowledge/document/__init__.py +5 -0
  118. agno/knowledge/document/base.py +58 -0
  119. agno/knowledge/embedder/__init__.py +5 -0
  120. agno/knowledge/embedder/aws_bedrock.py +343 -0
  121. agno/knowledge/embedder/azure_openai.py +210 -0
  122. agno/knowledge/embedder/base.py +23 -0
  123. agno/knowledge/embedder/cohere.py +323 -0
  124. agno/knowledge/embedder/fastembed.py +62 -0
  125. agno/knowledge/embedder/fireworks.py +13 -0
  126. agno/knowledge/embedder/google.py +258 -0
  127. agno/knowledge/embedder/huggingface.py +94 -0
  128. agno/knowledge/embedder/jina.py +182 -0
  129. agno/knowledge/embedder/langdb.py +22 -0
  130. agno/knowledge/embedder/mistral.py +206 -0
  131. agno/knowledge/embedder/nebius.py +13 -0
  132. agno/knowledge/embedder/ollama.py +154 -0
  133. agno/knowledge/embedder/openai.py +195 -0
  134. agno/knowledge/embedder/sentence_transformer.py +63 -0
  135. agno/knowledge/embedder/together.py +13 -0
  136. agno/knowledge/embedder/vllm.py +262 -0
  137. agno/knowledge/embedder/voyageai.py +165 -0
  138. agno/knowledge/knowledge.py +1988 -0
  139. agno/knowledge/reader/__init__.py +7 -0
  140. agno/knowledge/reader/arxiv_reader.py +81 -0
  141. agno/knowledge/reader/base.py +95 -0
  142. agno/knowledge/reader/csv_reader.py +166 -0
  143. agno/knowledge/reader/docx_reader.py +82 -0
  144. agno/knowledge/reader/field_labeled_csv_reader.py +292 -0
  145. agno/knowledge/reader/firecrawl_reader.py +201 -0
  146. agno/knowledge/reader/json_reader.py +87 -0
  147. agno/knowledge/reader/markdown_reader.py +137 -0
  148. agno/knowledge/reader/pdf_reader.py +431 -0
  149. agno/knowledge/reader/pptx_reader.py +101 -0
  150. agno/knowledge/reader/reader_factory.py +313 -0
  151. agno/knowledge/reader/s3_reader.py +89 -0
  152. agno/knowledge/reader/tavily_reader.py +194 -0
  153. agno/knowledge/reader/text_reader.py +115 -0
  154. agno/knowledge/reader/web_search_reader.py +372 -0
  155. agno/knowledge/reader/website_reader.py +455 -0
  156. agno/knowledge/reader/wikipedia_reader.py +59 -0
  157. agno/knowledge/reader/youtube_reader.py +78 -0
  158. agno/knowledge/remote_content/__init__.py +0 -0
  159. agno/knowledge/remote_content/remote_content.py +88 -0
  160. agno/knowledge/reranker/__init__.py +3 -0
  161. agno/knowledge/reranker/base.py +14 -0
  162. agno/knowledge/reranker/cohere.py +64 -0
  163. agno/knowledge/reranker/infinity.py +195 -0
  164. agno/knowledge/reranker/sentence_transformer.py +54 -0
  165. agno/knowledge/types.py +39 -0
  166. agno/knowledge/utils.py +189 -0
  167. agno/media.py +462 -0
  168. agno/memory/__init__.py +3 -0
  169. agno/memory/manager.py +1327 -0
  170. agno/models/__init__.py +0 -0
  171. agno/models/aimlapi/__init__.py +5 -0
  172. agno/models/aimlapi/aimlapi.py +45 -0
  173. agno/models/anthropic/__init__.py +5 -0
  174. agno/models/anthropic/claude.py +757 -0
  175. agno/models/aws/__init__.py +15 -0
  176. agno/models/aws/bedrock.py +701 -0
  177. agno/models/aws/claude.py +378 -0
  178. agno/models/azure/__init__.py +18 -0
  179. agno/models/azure/ai_foundry.py +485 -0
  180. agno/models/azure/openai_chat.py +131 -0
  181. agno/models/base.py +2175 -0
  182. agno/models/cerebras/__init__.py +12 -0
  183. agno/models/cerebras/cerebras.py +501 -0
  184. agno/models/cerebras/cerebras_openai.py +112 -0
  185. agno/models/cohere/__init__.py +5 -0
  186. agno/models/cohere/chat.py +389 -0
  187. agno/models/cometapi/__init__.py +5 -0
  188. agno/models/cometapi/cometapi.py +57 -0
  189. agno/models/dashscope/__init__.py +5 -0
  190. agno/models/dashscope/dashscope.py +91 -0
  191. agno/models/deepinfra/__init__.py +5 -0
  192. agno/models/deepinfra/deepinfra.py +28 -0
  193. agno/models/deepseek/__init__.py +5 -0
  194. agno/models/deepseek/deepseek.py +61 -0
  195. agno/models/defaults.py +1 -0
  196. agno/models/fireworks/__init__.py +5 -0
  197. agno/models/fireworks/fireworks.py +26 -0
  198. agno/models/google/__init__.py +5 -0
  199. agno/models/google/gemini.py +1085 -0
  200. agno/models/groq/__init__.py +5 -0
  201. agno/models/groq/groq.py +556 -0
  202. agno/models/huggingface/__init__.py +5 -0
  203. agno/models/huggingface/huggingface.py +491 -0
  204. agno/models/ibm/__init__.py +5 -0
  205. agno/models/ibm/watsonx.py +422 -0
  206. agno/models/internlm/__init__.py +3 -0
  207. agno/models/internlm/internlm.py +26 -0
  208. agno/models/langdb/__init__.py +1 -0
  209. agno/models/langdb/langdb.py +48 -0
  210. agno/models/litellm/__init__.py +14 -0
  211. agno/models/litellm/chat.py +468 -0
  212. agno/models/litellm/litellm_openai.py +25 -0
  213. agno/models/llama_cpp/__init__.py +5 -0
  214. agno/models/llama_cpp/llama_cpp.py +22 -0
  215. agno/models/lmstudio/__init__.py +5 -0
  216. agno/models/lmstudio/lmstudio.py +25 -0
  217. agno/models/message.py +434 -0
  218. agno/models/meta/__init__.py +12 -0
  219. agno/models/meta/llama.py +475 -0
  220. agno/models/meta/llama_openai.py +78 -0
  221. agno/models/metrics.py +120 -0
  222. agno/models/mistral/__init__.py +5 -0
  223. agno/models/mistral/mistral.py +432 -0
  224. agno/models/nebius/__init__.py +3 -0
  225. agno/models/nebius/nebius.py +54 -0
  226. agno/models/nexus/__init__.py +3 -0
  227. agno/models/nexus/nexus.py +22 -0
  228. agno/models/nvidia/__init__.py +5 -0
  229. agno/models/nvidia/nvidia.py +28 -0
  230. agno/models/ollama/__init__.py +5 -0
  231. agno/models/ollama/chat.py +441 -0
  232. agno/models/openai/__init__.py +9 -0
  233. agno/models/openai/chat.py +883 -0
  234. agno/models/openai/like.py +27 -0
  235. agno/models/openai/responses.py +1050 -0
  236. agno/models/openrouter/__init__.py +5 -0
  237. agno/models/openrouter/openrouter.py +66 -0
  238. agno/models/perplexity/__init__.py +5 -0
  239. agno/models/perplexity/perplexity.py +187 -0
  240. agno/models/portkey/__init__.py +3 -0
  241. agno/models/portkey/portkey.py +81 -0
  242. agno/models/requesty/__init__.py +5 -0
  243. agno/models/requesty/requesty.py +52 -0
  244. agno/models/response.py +199 -0
  245. agno/models/sambanova/__init__.py +5 -0
  246. agno/models/sambanova/sambanova.py +28 -0
  247. agno/models/siliconflow/__init__.py +5 -0
  248. agno/models/siliconflow/siliconflow.py +25 -0
  249. agno/models/together/__init__.py +5 -0
  250. agno/models/together/together.py +25 -0
  251. agno/models/utils.py +266 -0
  252. agno/models/vercel/__init__.py +3 -0
  253. agno/models/vercel/v0.py +26 -0
  254. agno/models/vertexai/__init__.py +0 -0
  255. agno/models/vertexai/claude.py +70 -0
  256. agno/models/vllm/__init__.py +3 -0
  257. agno/models/vllm/vllm.py +78 -0
  258. agno/models/xai/__init__.py +3 -0
  259. agno/models/xai/xai.py +113 -0
  260. agno/os/__init__.py +3 -0
  261. agno/os/app.py +876 -0
  262. agno/os/auth.py +57 -0
  263. agno/os/config.py +104 -0
  264. agno/os/interfaces/__init__.py +1 -0
  265. agno/os/interfaces/a2a/__init__.py +3 -0
  266. agno/os/interfaces/a2a/a2a.py +42 -0
  267. agno/os/interfaces/a2a/router.py +250 -0
  268. agno/os/interfaces/a2a/utils.py +924 -0
  269. agno/os/interfaces/agui/__init__.py +3 -0
  270. agno/os/interfaces/agui/agui.py +47 -0
  271. agno/os/interfaces/agui/router.py +144 -0
  272. agno/os/interfaces/agui/utils.py +534 -0
  273. agno/os/interfaces/base.py +25 -0
  274. agno/os/interfaces/slack/__init__.py +3 -0
  275. agno/os/interfaces/slack/router.py +148 -0
  276. agno/os/interfaces/slack/security.py +30 -0
  277. agno/os/interfaces/slack/slack.py +47 -0
  278. agno/os/interfaces/whatsapp/__init__.py +3 -0
  279. agno/os/interfaces/whatsapp/router.py +211 -0
  280. agno/os/interfaces/whatsapp/security.py +53 -0
  281. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  282. agno/os/mcp.py +292 -0
  283. agno/os/middleware/__init__.py +7 -0
  284. agno/os/middleware/jwt.py +233 -0
  285. agno/os/router.py +1763 -0
  286. agno/os/routers/__init__.py +3 -0
  287. agno/os/routers/evals/__init__.py +3 -0
  288. agno/os/routers/evals/evals.py +430 -0
  289. agno/os/routers/evals/schemas.py +142 -0
  290. agno/os/routers/evals/utils.py +162 -0
  291. agno/os/routers/health.py +31 -0
  292. agno/os/routers/home.py +52 -0
  293. agno/os/routers/knowledge/__init__.py +3 -0
  294. agno/os/routers/knowledge/knowledge.py +997 -0
  295. agno/os/routers/knowledge/schemas.py +178 -0
  296. agno/os/routers/memory/__init__.py +3 -0
  297. agno/os/routers/memory/memory.py +515 -0
  298. agno/os/routers/memory/schemas.py +62 -0
  299. agno/os/routers/metrics/__init__.py +3 -0
  300. agno/os/routers/metrics/metrics.py +190 -0
  301. agno/os/routers/metrics/schemas.py +47 -0
  302. agno/os/routers/session/__init__.py +3 -0
  303. agno/os/routers/session/session.py +997 -0
  304. agno/os/schema.py +1055 -0
  305. agno/os/settings.py +43 -0
  306. agno/os/utils.py +630 -0
  307. agno/py.typed +0 -0
  308. agno/reasoning/__init__.py +0 -0
  309. agno/reasoning/anthropic.py +80 -0
  310. agno/reasoning/azure_ai_foundry.py +67 -0
  311. agno/reasoning/deepseek.py +63 -0
  312. agno/reasoning/default.py +97 -0
  313. agno/reasoning/gemini.py +73 -0
  314. agno/reasoning/groq.py +71 -0
  315. agno/reasoning/helpers.py +63 -0
  316. agno/reasoning/ollama.py +67 -0
  317. agno/reasoning/openai.py +86 -0
  318. agno/reasoning/step.py +31 -0
  319. agno/reasoning/vertexai.py +76 -0
  320. agno/run/__init__.py +6 -0
  321. agno/run/agent.py +787 -0
  322. agno/run/base.py +229 -0
  323. agno/run/cancel.py +81 -0
  324. agno/run/messages.py +32 -0
  325. agno/run/team.py +753 -0
  326. agno/run/workflow.py +708 -0
  327. agno/session/__init__.py +10 -0
  328. agno/session/agent.py +295 -0
  329. agno/session/summary.py +265 -0
  330. agno/session/team.py +392 -0
  331. agno/session/workflow.py +205 -0
  332. agno/team/__init__.py +37 -0
  333. agno/team/team.py +8793 -0
  334. agno/tools/__init__.py +10 -0
  335. agno/tools/agentql.py +120 -0
  336. agno/tools/airflow.py +69 -0
  337. agno/tools/api.py +122 -0
  338. agno/tools/apify.py +314 -0
  339. agno/tools/arxiv.py +127 -0
  340. agno/tools/aws_lambda.py +53 -0
  341. agno/tools/aws_ses.py +66 -0
  342. agno/tools/baidusearch.py +89 -0
  343. agno/tools/bitbucket.py +292 -0
  344. agno/tools/brandfetch.py +213 -0
  345. agno/tools/bravesearch.py +106 -0
  346. agno/tools/brightdata.py +367 -0
  347. agno/tools/browserbase.py +209 -0
  348. agno/tools/calcom.py +255 -0
  349. agno/tools/calculator.py +151 -0
  350. agno/tools/cartesia.py +187 -0
  351. agno/tools/clickup.py +244 -0
  352. agno/tools/confluence.py +240 -0
  353. agno/tools/crawl4ai.py +158 -0
  354. agno/tools/csv_toolkit.py +185 -0
  355. agno/tools/dalle.py +110 -0
  356. agno/tools/daytona.py +475 -0
  357. agno/tools/decorator.py +262 -0
  358. agno/tools/desi_vocal.py +108 -0
  359. agno/tools/discord.py +161 -0
  360. agno/tools/docker.py +716 -0
  361. agno/tools/duckdb.py +379 -0
  362. agno/tools/duckduckgo.py +91 -0
  363. agno/tools/e2b.py +703 -0
  364. agno/tools/eleven_labs.py +196 -0
  365. agno/tools/email.py +67 -0
  366. agno/tools/evm.py +129 -0
  367. agno/tools/exa.py +396 -0
  368. agno/tools/fal.py +127 -0
  369. agno/tools/file.py +240 -0
  370. agno/tools/file_generation.py +350 -0
  371. agno/tools/financial_datasets.py +288 -0
  372. agno/tools/firecrawl.py +143 -0
  373. agno/tools/function.py +1187 -0
  374. agno/tools/giphy.py +93 -0
  375. agno/tools/github.py +1760 -0
  376. agno/tools/gmail.py +922 -0
  377. agno/tools/google_bigquery.py +117 -0
  378. agno/tools/google_drive.py +270 -0
  379. agno/tools/google_maps.py +253 -0
  380. agno/tools/googlecalendar.py +674 -0
  381. agno/tools/googlesearch.py +98 -0
  382. agno/tools/googlesheets.py +377 -0
  383. agno/tools/hackernews.py +77 -0
  384. agno/tools/jina.py +101 -0
  385. agno/tools/jira.py +170 -0
  386. agno/tools/knowledge.py +218 -0
  387. agno/tools/linear.py +426 -0
  388. agno/tools/linkup.py +58 -0
  389. agno/tools/local_file_system.py +90 -0
  390. agno/tools/lumalab.py +183 -0
  391. agno/tools/mcp/__init__.py +10 -0
  392. agno/tools/mcp/mcp.py +331 -0
  393. agno/tools/mcp/multi_mcp.py +347 -0
  394. agno/tools/mcp/params.py +24 -0
  395. agno/tools/mcp_toolbox.py +284 -0
  396. agno/tools/mem0.py +193 -0
  397. agno/tools/memori.py +339 -0
  398. agno/tools/memory.py +419 -0
  399. agno/tools/mlx_transcribe.py +139 -0
  400. agno/tools/models/__init__.py +0 -0
  401. agno/tools/models/azure_openai.py +190 -0
  402. agno/tools/models/gemini.py +203 -0
  403. agno/tools/models/groq.py +158 -0
  404. agno/tools/models/morph.py +186 -0
  405. agno/tools/models/nebius.py +124 -0
  406. agno/tools/models_labs.py +195 -0
  407. agno/tools/moviepy_video.py +349 -0
  408. agno/tools/neo4j.py +134 -0
  409. agno/tools/newspaper.py +46 -0
  410. agno/tools/newspaper4k.py +93 -0
  411. agno/tools/notion.py +204 -0
  412. agno/tools/openai.py +202 -0
  413. agno/tools/openbb.py +160 -0
  414. agno/tools/opencv.py +321 -0
  415. agno/tools/openweather.py +233 -0
  416. agno/tools/oxylabs.py +385 -0
  417. agno/tools/pandas.py +102 -0
  418. agno/tools/parallel.py +314 -0
  419. agno/tools/postgres.py +257 -0
  420. agno/tools/pubmed.py +188 -0
  421. agno/tools/python.py +205 -0
  422. agno/tools/reasoning.py +283 -0
  423. agno/tools/reddit.py +467 -0
  424. agno/tools/replicate.py +117 -0
  425. agno/tools/resend.py +62 -0
  426. agno/tools/scrapegraph.py +222 -0
  427. agno/tools/searxng.py +152 -0
  428. agno/tools/serpapi.py +116 -0
  429. agno/tools/serper.py +255 -0
  430. agno/tools/shell.py +53 -0
  431. agno/tools/slack.py +136 -0
  432. agno/tools/sleep.py +20 -0
  433. agno/tools/spider.py +116 -0
  434. agno/tools/sql.py +154 -0
  435. agno/tools/streamlit/__init__.py +0 -0
  436. agno/tools/streamlit/components.py +113 -0
  437. agno/tools/tavily.py +254 -0
  438. agno/tools/telegram.py +48 -0
  439. agno/tools/todoist.py +218 -0
  440. agno/tools/tool_registry.py +1 -0
  441. agno/tools/toolkit.py +146 -0
  442. agno/tools/trafilatura.py +388 -0
  443. agno/tools/trello.py +274 -0
  444. agno/tools/twilio.py +186 -0
  445. agno/tools/user_control_flow.py +78 -0
  446. agno/tools/valyu.py +228 -0
  447. agno/tools/visualization.py +467 -0
  448. agno/tools/webbrowser.py +28 -0
  449. agno/tools/webex.py +76 -0
  450. agno/tools/website.py +54 -0
  451. agno/tools/webtools.py +45 -0
  452. agno/tools/whatsapp.py +286 -0
  453. agno/tools/wikipedia.py +63 -0
  454. agno/tools/workflow.py +278 -0
  455. agno/tools/x.py +335 -0
  456. agno/tools/yfinance.py +257 -0
  457. agno/tools/youtube.py +184 -0
  458. agno/tools/zendesk.py +82 -0
  459. agno/tools/zep.py +454 -0
  460. agno/tools/zoom.py +382 -0
  461. agno/utils/__init__.py +0 -0
  462. agno/utils/agent.py +820 -0
  463. agno/utils/audio.py +49 -0
  464. agno/utils/certs.py +27 -0
  465. agno/utils/code_execution.py +11 -0
  466. agno/utils/common.py +132 -0
  467. agno/utils/dttm.py +13 -0
  468. agno/utils/enum.py +22 -0
  469. agno/utils/env.py +11 -0
  470. agno/utils/events.py +696 -0
  471. agno/utils/format_str.py +16 -0
  472. agno/utils/functions.py +166 -0
  473. agno/utils/gemini.py +426 -0
  474. agno/utils/hooks.py +57 -0
  475. agno/utils/http.py +74 -0
  476. agno/utils/json_schema.py +234 -0
  477. agno/utils/knowledge.py +36 -0
  478. agno/utils/location.py +19 -0
  479. agno/utils/log.py +255 -0
  480. agno/utils/mcp.py +214 -0
  481. agno/utils/media.py +352 -0
  482. agno/utils/merge_dict.py +41 -0
  483. agno/utils/message.py +118 -0
  484. agno/utils/models/__init__.py +0 -0
  485. agno/utils/models/ai_foundry.py +43 -0
  486. agno/utils/models/claude.py +358 -0
  487. agno/utils/models/cohere.py +87 -0
  488. agno/utils/models/llama.py +78 -0
  489. agno/utils/models/mistral.py +98 -0
  490. agno/utils/models/openai_responses.py +140 -0
  491. agno/utils/models/schema_utils.py +153 -0
  492. agno/utils/models/watsonx.py +41 -0
  493. agno/utils/openai.py +257 -0
  494. agno/utils/pickle.py +32 -0
  495. agno/utils/pprint.py +178 -0
  496. agno/utils/print_response/__init__.py +0 -0
  497. agno/utils/print_response/agent.py +842 -0
  498. agno/utils/print_response/team.py +1724 -0
  499. agno/utils/print_response/workflow.py +1668 -0
  500. agno/utils/prompts.py +111 -0
  501. agno/utils/reasoning.py +108 -0
  502. agno/utils/response.py +163 -0
  503. agno/utils/response_iterator.py +17 -0
  504. agno/utils/safe_formatter.py +24 -0
  505. agno/utils/serialize.py +32 -0
  506. agno/utils/shell.py +22 -0
  507. agno/utils/streamlit.py +487 -0
  508. agno/utils/string.py +231 -0
  509. agno/utils/team.py +139 -0
  510. agno/utils/timer.py +41 -0
  511. agno/utils/tools.py +102 -0
  512. agno/utils/web.py +23 -0
  513. agno/utils/whatsapp.py +305 -0
  514. agno/utils/yaml_io.py +25 -0
  515. agno/vectordb/__init__.py +3 -0
  516. agno/vectordb/base.py +127 -0
  517. agno/vectordb/cassandra/__init__.py +5 -0
  518. agno/vectordb/cassandra/cassandra.py +501 -0
  519. agno/vectordb/cassandra/extra_param_mixin.py +11 -0
  520. agno/vectordb/cassandra/index.py +13 -0
  521. agno/vectordb/chroma/__init__.py +5 -0
  522. agno/vectordb/chroma/chromadb.py +929 -0
  523. agno/vectordb/clickhouse/__init__.py +9 -0
  524. agno/vectordb/clickhouse/clickhousedb.py +835 -0
  525. agno/vectordb/clickhouse/index.py +9 -0
  526. agno/vectordb/couchbase/__init__.py +3 -0
  527. agno/vectordb/couchbase/couchbase.py +1442 -0
  528. agno/vectordb/distance.py +7 -0
  529. agno/vectordb/lancedb/__init__.py +6 -0
  530. agno/vectordb/lancedb/lance_db.py +995 -0
  531. agno/vectordb/langchaindb/__init__.py +5 -0
  532. agno/vectordb/langchaindb/langchaindb.py +163 -0
  533. agno/vectordb/lightrag/__init__.py +5 -0
  534. agno/vectordb/lightrag/lightrag.py +388 -0
  535. agno/vectordb/llamaindex/__init__.py +3 -0
  536. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  537. agno/vectordb/milvus/__init__.py +4 -0
  538. agno/vectordb/milvus/milvus.py +1182 -0
  539. agno/vectordb/mongodb/__init__.py +9 -0
  540. agno/vectordb/mongodb/mongodb.py +1417 -0
  541. agno/vectordb/pgvector/__init__.py +12 -0
  542. agno/vectordb/pgvector/index.py +23 -0
  543. agno/vectordb/pgvector/pgvector.py +1462 -0
  544. agno/vectordb/pineconedb/__init__.py +5 -0
  545. agno/vectordb/pineconedb/pineconedb.py +747 -0
  546. agno/vectordb/qdrant/__init__.py +5 -0
  547. agno/vectordb/qdrant/qdrant.py +1134 -0
  548. agno/vectordb/redis/__init__.py +9 -0
  549. agno/vectordb/redis/redisdb.py +694 -0
  550. agno/vectordb/search.py +7 -0
  551. agno/vectordb/singlestore/__init__.py +10 -0
  552. agno/vectordb/singlestore/index.py +41 -0
  553. agno/vectordb/singlestore/singlestore.py +763 -0
  554. agno/vectordb/surrealdb/__init__.py +3 -0
  555. agno/vectordb/surrealdb/surrealdb.py +699 -0
  556. agno/vectordb/upstashdb/__init__.py +5 -0
  557. agno/vectordb/upstashdb/upstashdb.py +718 -0
  558. agno/vectordb/weaviate/__init__.py +8 -0
  559. agno/vectordb/weaviate/index.py +15 -0
  560. agno/vectordb/weaviate/weaviate.py +1005 -0
  561. agno/workflow/__init__.py +23 -0
  562. agno/workflow/agent.py +299 -0
  563. agno/workflow/condition.py +738 -0
  564. agno/workflow/loop.py +735 -0
  565. agno/workflow/parallel.py +824 -0
  566. agno/workflow/router.py +702 -0
  567. agno/workflow/step.py +1432 -0
  568. agno/workflow/steps.py +592 -0
  569. agno/workflow/types.py +520 -0
  570. agno/workflow/workflow.py +4321 -0
  571. agno-2.2.13.dist-info/METADATA +614 -0
  572. agno-2.2.13.dist-info/RECORD +575 -0
  573. agno-2.2.13.dist-info/WHEEL +5 -0
  574. agno-2.2.13.dist-info/licenses/LICENSE +201 -0
  575. agno-2.2.13.dist-info/top_level.txt +1 -0
@@ -0,0 +1,485 @@
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
+ raise ValueError("API key is required")
140
+ if not self.azure_endpoint:
141
+ raise ValueError("Endpoint URL is required")
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
+ ) -> ModelResponse:
211
+ """
212
+ Send a chat completion request to the Azure AI API.
213
+ """
214
+ try:
215
+ if run_response and run_response.metrics:
216
+ run_response.metrics.set_time_to_first_token()
217
+
218
+ assistant_message.metrics.start_timer()
219
+ provider_response = self.get_client().complete(
220
+ messages=[format_message(m) for m in messages],
221
+ **self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
222
+ )
223
+ assistant_message.metrics.stop_timer()
224
+
225
+ model_response = self._parse_provider_response(provider_response, response_format=response_format)
226
+
227
+ return model_response
228
+
229
+ except HttpResponseError as e:
230
+ log_error(f"Azure AI API error: {e}")
231
+ raise ModelProviderError(
232
+ message=e.reason or "Azure AI API error",
233
+ status_code=e.status_code or 502,
234
+ model_name=self.name,
235
+ model_id=self.id,
236
+ ) from e
237
+ except Exception as e:
238
+ log_error(f"Error from Azure AI API: {e}")
239
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
240
+
241
+ async def ainvoke(
242
+ self,
243
+ messages: List[Message],
244
+ assistant_message: Message,
245
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
246
+ tools: Optional[List[Dict[str, Any]]] = None,
247
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
248
+ run_response: Optional[RunOutput] = None,
249
+ ) -> ModelResponse:
250
+ """
251
+ Sends an asynchronous chat completion request to the Azure AI API.
252
+ """
253
+
254
+ try:
255
+ if run_response and run_response.metrics:
256
+ run_response.metrics.set_time_to_first_token()
257
+
258
+ assistant_message.metrics.start_timer()
259
+ provider_response = await self.get_async_client().complete(
260
+ messages=[format_message(m) for m in messages],
261
+ **self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
262
+ )
263
+ assistant_message.metrics.stop_timer()
264
+
265
+ model_response = self._parse_provider_response(provider_response, response_format=response_format) # type: ignore
266
+
267
+ return model_response
268
+
269
+ except HttpResponseError as e:
270
+ log_error(f"Azure AI API error: {e}")
271
+ raise ModelProviderError(
272
+ message=e.reason or "Azure AI API error",
273
+ status_code=e.status_code or 502,
274
+ model_name=self.name,
275
+ model_id=self.id,
276
+ ) from e
277
+ except Exception as e:
278
+ log_error(f"Error from Azure AI API: {e}")
279
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
280
+
281
+ def invoke_stream(
282
+ self,
283
+ messages: List[Message],
284
+ assistant_message: Message,
285
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
286
+ tools: Optional[List[Dict[str, Any]]] = None,
287
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
288
+ run_response: Optional[RunOutput] = None,
289
+ ) -> Iterator[ModelResponse]:
290
+ """
291
+ Send a streaming chat completion request to the Azure AI API.
292
+ """
293
+ try:
294
+ if run_response and run_response.metrics:
295
+ run_response.metrics.set_time_to_first_token()
296
+
297
+ assistant_message.metrics.start_timer()
298
+
299
+ for chunk in self.get_client().complete(
300
+ messages=[format_message(m) for m in messages],
301
+ stream=True,
302
+ **self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
303
+ ):
304
+ yield self._parse_provider_response_delta(chunk)
305
+
306
+ assistant_message.metrics.stop_timer()
307
+
308
+ except HttpResponseError as e:
309
+ log_error(f"Azure AI API error: {e}")
310
+ raise ModelProviderError(
311
+ message=e.reason or "Azure AI API error",
312
+ status_code=e.status_code or 502,
313
+ model_name=self.name,
314
+ model_id=self.id,
315
+ ) from e
316
+ except Exception as e:
317
+ log_error(f"Error from Azure AI API: {e}")
318
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
319
+
320
+ async def ainvoke_stream(
321
+ self,
322
+ messages: List[Message],
323
+ assistant_message: Message,
324
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
325
+ tools: Optional[List[Dict[str, Any]]] = None,
326
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
327
+ run_response: Optional[RunOutput] = None,
328
+ ) -> AsyncIterator[ModelResponse]:
329
+ """
330
+ Sends an asynchronous streaming chat completion request to the Azure AI API.
331
+ """
332
+ try:
333
+ if run_response and run_response.metrics:
334
+ run_response.metrics.set_time_to_first_token()
335
+
336
+ assistant_message.metrics.start_timer()
337
+
338
+ async_stream = await self.get_async_client().complete(
339
+ messages=[format_message(m) for m in messages],
340
+ stream=True,
341
+ **self.get_request_params(tools=tools, response_format=response_format, tool_choice=tool_choice),
342
+ )
343
+ async for chunk in async_stream: # type: ignore
344
+ yield self._parse_provider_response_delta(chunk)
345
+
346
+ assistant_message.metrics.stop_timer()
347
+
348
+ except HttpResponseError as e:
349
+ log_error(f"Azure AI API error: {e}")
350
+ raise ModelProviderError(
351
+ message=e.reason or "Azure AI API error",
352
+ status_code=e.status_code or 502,
353
+ model_name=self.name,
354
+ model_id=self.id,
355
+ ) from e
356
+ except Exception as e:
357
+ log_error(f"Error from Azure AI API: {e}")
358
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
359
+
360
+ def _parse_provider_response(self, response: ChatCompletions, **kwargs) -> ModelResponse:
361
+ """
362
+ Parse the Azure AI response into a ModelResponse.
363
+
364
+ Args:
365
+ response: Raw response from Azure AI
366
+
367
+ Returns:
368
+ ModelResponse: Parsed response data
369
+ """
370
+ model_response = ModelResponse()
371
+
372
+ try:
373
+ # Get the first choice from the response
374
+ choice = response.choices[0]
375
+
376
+ # Add content
377
+ if choice.message.content is not None:
378
+ model_response.content = choice.message.content
379
+
380
+ # Add role
381
+ if choice.message.role is not None:
382
+ model_response.role = choice.message.role
383
+
384
+ # Add tool calls if present
385
+ if choice.message.tool_calls and len(choice.message.tool_calls) > 0:
386
+ model_response.tool_calls = [
387
+ {
388
+ "id": t.id,
389
+ "type": t.type,
390
+ "function": {
391
+ "name": t.function.name,
392
+ "arguments": t.function.arguments,
393
+ },
394
+ }
395
+ for t in choice.message.tool_calls
396
+ ]
397
+
398
+ # Add usage metrics if present
399
+ if response.usage is not None:
400
+ model_response.response_usage = self._get_metrics(response.usage)
401
+
402
+ except Exception as e:
403
+ log_error(f"Error parsing Azure AI response: {e}")
404
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
405
+
406
+ return model_response
407
+
408
+ # Override base method
409
+ @staticmethod
410
+ def parse_tool_calls(tool_calls_data: List[StreamingChatResponseToolCallUpdate]) -> List[Dict[str, Any]]:
411
+ """
412
+ Build tool calls from streamed tool call data.
413
+
414
+ Args:
415
+ tool_calls_data (List[StreamingChatResponseToolCallUpdate]): The tool call data to build from.
416
+
417
+ Returns:
418
+ List[Dict[str, Any]]: The built tool calls.
419
+ """
420
+ tool_calls: List[Dict[str, Any]] = []
421
+
422
+ current_tool_call: Dict[str, Any] = {}
423
+ for tool_call in tool_calls_data:
424
+ if tool_call.id: # New tool call starts
425
+ if current_tool_call: # Store previous tool call if exists
426
+ tool_calls.append(current_tool_call)
427
+ current_tool_call = {
428
+ "id": tool_call.id,
429
+ "type": "function",
430
+ "function": {"name": tool_call.function.name, "arguments": tool_call.function.arguments or ""},
431
+ }
432
+ elif current_tool_call and tool_call.function and tool_call.function.arguments:
433
+ # Append arguments to current tool call
434
+ current_tool_call["function"]["arguments"] += tool_call.function.arguments
435
+
436
+ if current_tool_call: # Append final tool call
437
+ tool_calls.append(current_tool_call)
438
+
439
+ return tool_calls
440
+
441
+ def _parse_provider_response_delta(self, response_delta: StreamingChatCompletionsUpdate) -> ModelResponse:
442
+ """
443
+ Parse the Azure AI streaming response into ModelResponse objects.
444
+
445
+ Args:
446
+ response_delta: Raw response chunk from Azure AI
447
+
448
+ Returns:
449
+ ModelResponse: Parsed response data
450
+ """
451
+ model_response = ModelResponse()
452
+
453
+ try:
454
+ if response_delta.choices and len(response_delta.choices) > 0:
455
+ choice_delta = response_delta.choices[0].delta
456
+
457
+ if choice_delta:
458
+ # Add content
459
+ if choice_delta.content is not None:
460
+ model_response.content = choice_delta.content
461
+
462
+ # Add tool calls if present
463
+ if choice_delta.tool_calls and len(choice_delta.tool_calls) > 0:
464
+ model_response.tool_calls = choice_delta.tool_calls # type: ignore
465
+ # Add usage metrics if present
466
+ if response_delta.usage is not None:
467
+ model_response.response_usage = self._get_metrics(response_delta.usage)
468
+
469
+ except Exception as e:
470
+ log_error(f"Error parsing Azure AI response delta: {e}")
471
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
472
+
473
+ return model_response
474
+
475
+ def _get_metrics(self, response_usage) -> Metrics:
476
+ """
477
+ Parse the given Azure AI Foundry usage into an Agno Metrics object.
478
+ """
479
+ metrics = Metrics()
480
+
481
+ metrics.input_tokens = response_usage.get("prompt_tokens", 0)
482
+ metrics.output_tokens = response_usage.get("completion_tokens", 0)
483
+ metrics.total_tokens = metrics.input_tokens + metrics.output_tokens
484
+
485
+ return metrics
@@ -0,0 +1,131 @@
1
+ from dataclasses import dataclass
2
+ from os import getenv
3
+ from typing import Any, Dict, Optional
4
+
5
+ import httpx
6
+
7
+ from agno.models.openai.like import OpenAILike
8
+ from agno.utils.log import log_debug
9
+
10
+ try:
11
+ from openai import AsyncAzureOpenAI as AsyncAzureOpenAIClient
12
+ from openai import AzureOpenAI as AzureOpenAIClient
13
+ except ImportError:
14
+ raise ImportError("`openai` not installed. Please install using `pip install openai`")
15
+
16
+
17
+ @dataclass
18
+ class AzureOpenAI(OpenAILike):
19
+ """
20
+ Azure OpenAI Chat model
21
+
22
+ Args:
23
+
24
+ id (str): The model name to use.
25
+ name (str): The model name to use.
26
+ provider (str): The provider to use.
27
+ api_key (Optional[str]): The API key to use.
28
+ api_version (str): The API version to use.
29
+ azure_endpoint (Optional[str]): The Azure endpoint to use.
30
+ azure_deployment (Optional[str]): The Azure deployment to use.
31
+ base_url (Optional[str]): The base URL to use.
32
+ azure_ad_token (Optional[str]): The Azure AD token to use.
33
+ azure_ad_token_provider (Optional[Any]): The Azure AD token provider to use.
34
+ organization (Optional[str]): The organization to use.
35
+ client (Optional[AzureOpenAIClient]): The OpenAI client to use.
36
+ async_client (Optional[AsyncAzureOpenAIClient]): The OpenAI client to use.
37
+ """
38
+
39
+ id: str
40
+ name: str = "AzureOpenAI"
41
+ provider: str = "Azure"
42
+
43
+ supports_native_structured_outputs: bool = True
44
+
45
+ api_key: Optional[str] = None
46
+ api_version: Optional[str] = "2024-10-21"
47
+ azure_endpoint: Optional[str] = None
48
+ azure_deployment: Optional[str] = None
49
+ base_url: Optional[str] = None
50
+ azure_ad_token: Optional[str] = None
51
+ azure_ad_token_provider: Optional[Any] = None
52
+
53
+ default_headers: Optional[Dict[str, str]] = None
54
+ default_query: Optional[Dict[str, Any]] = None
55
+
56
+ client: Optional[AzureOpenAIClient] = None
57
+ async_client: Optional[AsyncAzureOpenAIClient] = None
58
+
59
+ def _get_client_params(self) -> Dict[str, Any]:
60
+ _client_params: Dict[str, Any] = {}
61
+
62
+ self.api_key = self.api_key or getenv("AZURE_OPENAI_API_KEY")
63
+ self.azure_endpoint = self.azure_endpoint or getenv("AZURE_OPENAI_ENDPOINT")
64
+ self.azure_deployment = self.azure_deployment or getenv("AZURE_OPENAI_DEPLOYMENT")
65
+ params_mapping = {
66
+ "api_key": self.api_key,
67
+ "api_version": self.api_version,
68
+ "organization": self.organization,
69
+ "azure_endpoint": self.azure_endpoint,
70
+ "azure_deployment": self.azure_deployment,
71
+ "base_url": self.base_url,
72
+ "azure_ad_token": self.azure_ad_token,
73
+ "azure_ad_token_provider": self.azure_ad_token_provider,
74
+ }
75
+ if self.default_headers is not None:
76
+ _client_params["default_headers"] = self.default_headers
77
+ if self.default_query is not None:
78
+ _client_params["default_query"] = self.default_query
79
+
80
+ _client_params.update({k: v for k, v in params_mapping.items() if v is not None})
81
+ if self.client_params:
82
+ _client_params.update(self.client_params)
83
+ return _client_params
84
+
85
+ def get_client(self) -> AzureOpenAIClient:
86
+ """
87
+ Get the OpenAI client.
88
+
89
+ Returns:
90
+ AzureOpenAIClient: The OpenAI client.
91
+
92
+ """
93
+ if self.client is not None and not self.client.is_closed():
94
+ return self.client
95
+
96
+ _client_params: Dict[str, Any] = self._get_client_params()
97
+
98
+ if self.http_client:
99
+ if isinstance(self.http_client, httpx.Client):
100
+ _client_params["http_client"] = self.http_client
101
+ else:
102
+ log_debug("http_client is not an instance of httpx.Client.")
103
+
104
+ # Create client
105
+ self.client = AzureOpenAIClient(**_client_params)
106
+ return self.client
107
+
108
+ def get_async_client(self) -> AsyncAzureOpenAIClient:
109
+ """
110
+ Returns an asynchronous OpenAI client.
111
+
112
+ Returns:
113
+ AsyncAzureOpenAIClient: An instance of the asynchronous OpenAI client.
114
+ """
115
+ if self.async_client and not self.async_client.is_closed():
116
+ return self.async_client
117
+
118
+ _client_params: Dict[str, Any] = self._get_client_params()
119
+
120
+ if self.http_client and isinstance(self.http_client, httpx.AsyncClient):
121
+ _client_params["http_client"] = self.http_client
122
+ else:
123
+ if self.http_client:
124
+ log_debug("The current http_client is not async. A default httpx.AsyncClient will be used instead.")
125
+ # Create a new async HTTP client with custom limits
126
+ _client_params["http_client"] = httpx.AsyncClient(
127
+ limits=httpx.Limits(max_connections=1000, max_keepalive_connections=100)
128
+ )
129
+
130
+ self.async_client = AsyncAzureOpenAIClient(**_client_params)
131
+ return self.async_client