agno 1.8.2__py3-none-any.whl → 2.0.0__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 (589) hide show
  1. agno/agent/__init__.py +19 -27
  2. agno/agent/agent.py +3143 -4170
  3. agno/api/agent.py +11 -67
  4. agno/api/api.py +5 -46
  5. agno/api/evals.py +8 -19
  6. agno/api/os.py +17 -0
  7. agno/api/routes.py +6 -41
  8. agno/api/schemas/__init__.py +9 -0
  9. agno/api/schemas/agent.py +5 -21
  10. agno/api/schemas/evals.py +7 -16
  11. agno/api/schemas/os.py +14 -0
  12. agno/api/schemas/team.py +5 -21
  13. agno/api/schemas/utils.py +21 -0
  14. agno/api/schemas/workflows.py +11 -7
  15. agno/api/settings.py +53 -0
  16. agno/api/team.py +11 -66
  17. agno/api/workflow.py +28 -0
  18. agno/cloud/aws/base.py +214 -0
  19. agno/cloud/aws/s3/__init__.py +2 -0
  20. agno/cloud/aws/s3/api_client.py +43 -0
  21. agno/cloud/aws/s3/bucket.py +195 -0
  22. agno/cloud/aws/s3/object.py +57 -0
  23. agno/db/__init__.py +24 -0
  24. agno/db/base.py +245 -0
  25. agno/db/dynamo/__init__.py +3 -0
  26. agno/db/dynamo/dynamo.py +1743 -0
  27. agno/db/dynamo/schemas.py +278 -0
  28. agno/db/dynamo/utils.py +684 -0
  29. agno/db/firestore/__init__.py +3 -0
  30. agno/db/firestore/firestore.py +1432 -0
  31. agno/db/firestore/schemas.py +130 -0
  32. agno/db/firestore/utils.py +278 -0
  33. agno/db/gcs_json/__init__.py +3 -0
  34. agno/db/gcs_json/gcs_json_db.py +1001 -0
  35. agno/db/gcs_json/utils.py +194 -0
  36. agno/db/in_memory/__init__.py +3 -0
  37. agno/db/in_memory/in_memory_db.py +882 -0
  38. agno/db/in_memory/utils.py +172 -0
  39. agno/db/json/__init__.py +3 -0
  40. agno/db/json/json_db.py +1045 -0
  41. agno/db/json/utils.py +196 -0
  42. agno/db/migrations/v1_to_v2.py +162 -0
  43. agno/db/mongo/__init__.py +3 -0
  44. agno/db/mongo/mongo.py +1416 -0
  45. agno/db/mongo/schemas.py +77 -0
  46. agno/db/mongo/utils.py +204 -0
  47. agno/db/mysql/__init__.py +3 -0
  48. agno/db/mysql/mysql.py +1719 -0
  49. agno/db/mysql/schemas.py +124 -0
  50. agno/db/mysql/utils.py +297 -0
  51. agno/db/postgres/__init__.py +3 -0
  52. agno/db/postgres/postgres.py +1710 -0
  53. agno/db/postgres/schemas.py +124 -0
  54. agno/db/postgres/utils.py +280 -0
  55. agno/db/redis/__init__.py +3 -0
  56. agno/db/redis/redis.py +1367 -0
  57. agno/db/redis/schemas.py +109 -0
  58. agno/db/redis/utils.py +288 -0
  59. agno/db/schemas/__init__.py +3 -0
  60. agno/db/schemas/evals.py +33 -0
  61. agno/db/schemas/knowledge.py +40 -0
  62. agno/db/schemas/memory.py +46 -0
  63. agno/db/singlestore/__init__.py +3 -0
  64. agno/db/singlestore/schemas.py +116 -0
  65. agno/db/singlestore/singlestore.py +1712 -0
  66. agno/db/singlestore/utils.py +326 -0
  67. agno/db/sqlite/__init__.py +3 -0
  68. agno/db/sqlite/schemas.py +119 -0
  69. agno/db/sqlite/sqlite.py +1676 -0
  70. agno/db/sqlite/utils.py +268 -0
  71. agno/db/utils.py +88 -0
  72. agno/eval/__init__.py +14 -0
  73. agno/eval/accuracy.py +154 -48
  74. agno/eval/performance.py +88 -23
  75. agno/eval/reliability.py +73 -20
  76. agno/eval/utils.py +23 -13
  77. agno/integrations/discord/__init__.py +3 -0
  78. agno/{app → integrations}/discord/client.py +10 -10
  79. agno/knowledge/__init__.py +2 -2
  80. agno/{document → knowledge}/chunking/agentic.py +2 -2
  81. agno/{document → knowledge}/chunking/document.py +2 -2
  82. agno/{document → knowledge}/chunking/fixed.py +3 -3
  83. agno/{document → knowledge}/chunking/markdown.py +2 -2
  84. agno/{document → knowledge}/chunking/recursive.py +2 -2
  85. agno/{document → knowledge}/chunking/row.py +2 -2
  86. agno/knowledge/chunking/semantic.py +59 -0
  87. agno/knowledge/chunking/strategy.py +121 -0
  88. agno/knowledge/content.py +74 -0
  89. agno/knowledge/document/__init__.py +5 -0
  90. agno/{document → knowledge/document}/base.py +12 -2
  91. agno/knowledge/embedder/__init__.py +5 -0
  92. agno/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
  93. agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
  94. agno/{embedder → knowledge/embedder}/base.py +6 -0
  95. agno/{embedder → knowledge/embedder}/cohere.py +72 -1
  96. agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
  97. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  98. agno/{embedder → knowledge/embedder}/google.py +74 -1
  99. agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
  100. agno/{embedder → knowledge/embedder}/jina.py +48 -2
  101. agno/knowledge/embedder/langdb.py +22 -0
  102. agno/knowledge/embedder/mistral.py +139 -0
  103. agno/{embedder → knowledge/embedder}/nebius.py +1 -1
  104. agno/{embedder → knowledge/embedder}/ollama.py +54 -3
  105. agno/knowledge/embedder/openai.py +223 -0
  106. agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
  107. agno/{embedder → knowledge/embedder}/together.py +1 -1
  108. agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
  109. agno/knowledge/knowledge.py +1551 -0
  110. agno/knowledge/reader/__init__.py +7 -0
  111. agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
  112. agno/knowledge/reader/base.py +88 -0
  113. agno/{document → knowledge}/reader/csv_reader.py +47 -65
  114. agno/knowledge/reader/docx_reader.py +83 -0
  115. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  116. agno/{document → knowledge}/reader/json_reader.py +30 -9
  117. agno/{document → knowledge}/reader/markdown_reader.py +58 -9
  118. agno/{document → knowledge}/reader/pdf_reader.py +71 -126
  119. agno/knowledge/reader/reader_factory.py +268 -0
  120. agno/knowledge/reader/s3_reader.py +101 -0
  121. agno/{document → knowledge}/reader/text_reader.py +31 -10
  122. agno/knowledge/reader/url_reader.py +128 -0
  123. agno/knowledge/reader/web_search_reader.py +366 -0
  124. agno/{document → knowledge}/reader/website_reader.py +37 -10
  125. agno/knowledge/reader/wikipedia_reader.py +59 -0
  126. agno/knowledge/reader/youtube_reader.py +78 -0
  127. agno/knowledge/remote_content/remote_content.py +88 -0
  128. agno/{reranker → knowledge/reranker}/base.py +1 -1
  129. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  130. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  131. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  132. agno/knowledge/types.py +30 -0
  133. agno/knowledge/utils.py +169 -0
  134. agno/media.py +269 -268
  135. agno/memory/__init__.py +2 -10
  136. agno/memory/manager.py +1003 -148
  137. agno/models/aimlapi/__init__.py +2 -2
  138. agno/models/aimlapi/aimlapi.py +6 -6
  139. agno/models/anthropic/claude.py +128 -72
  140. agno/models/aws/bedrock.py +107 -175
  141. agno/models/aws/claude.py +64 -18
  142. agno/models/azure/ai_foundry.py +73 -23
  143. agno/models/base.py +346 -290
  144. agno/models/cerebras/cerebras.py +84 -27
  145. agno/models/cohere/chat.py +106 -98
  146. agno/models/google/gemini.py +105 -46
  147. agno/models/groq/groq.py +97 -35
  148. agno/models/huggingface/huggingface.py +92 -27
  149. agno/models/ibm/watsonx.py +72 -13
  150. agno/models/litellm/chat.py +85 -13
  151. agno/models/message.py +46 -151
  152. agno/models/meta/llama.py +85 -49
  153. agno/models/metrics.py +120 -0
  154. agno/models/mistral/mistral.py +90 -21
  155. agno/models/ollama/__init__.py +0 -2
  156. agno/models/ollama/chat.py +85 -47
  157. agno/models/openai/chat.py +154 -37
  158. agno/models/openai/responses.py +178 -105
  159. agno/models/perplexity/perplexity.py +26 -2
  160. agno/models/portkey/portkey.py +0 -7
  161. agno/models/response.py +15 -9
  162. agno/models/utils.py +20 -0
  163. agno/models/vercel/__init__.py +2 -2
  164. agno/models/vercel/v0.py +1 -1
  165. agno/models/vllm/__init__.py +2 -2
  166. agno/models/vllm/vllm.py +3 -3
  167. agno/models/xai/xai.py +10 -10
  168. agno/os/__init__.py +3 -0
  169. agno/os/app.py +497 -0
  170. agno/os/auth.py +47 -0
  171. agno/os/config.py +103 -0
  172. agno/os/interfaces/agui/__init__.py +3 -0
  173. agno/os/interfaces/agui/agui.py +31 -0
  174. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  175. agno/{app → os/interfaces}/agui/utils.py +65 -28
  176. agno/os/interfaces/base.py +21 -0
  177. agno/os/interfaces/slack/__init__.py +3 -0
  178. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  179. agno/os/interfaces/slack/slack.py +32 -0
  180. agno/os/interfaces/whatsapp/__init__.py +3 -0
  181. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  182. agno/os/interfaces/whatsapp/whatsapp.py +29 -0
  183. agno/os/mcp.py +235 -0
  184. agno/os/router.py +1400 -0
  185. agno/os/routers/__init__.py +3 -0
  186. agno/os/routers/evals/__init__.py +3 -0
  187. agno/os/routers/evals/evals.py +393 -0
  188. agno/os/routers/evals/schemas.py +142 -0
  189. agno/os/routers/evals/utils.py +161 -0
  190. agno/os/routers/knowledge/__init__.py +3 -0
  191. agno/os/routers/knowledge/knowledge.py +850 -0
  192. agno/os/routers/knowledge/schemas.py +118 -0
  193. agno/os/routers/memory/__init__.py +3 -0
  194. agno/os/routers/memory/memory.py +410 -0
  195. agno/os/routers/memory/schemas.py +58 -0
  196. agno/os/routers/metrics/__init__.py +3 -0
  197. agno/os/routers/metrics/metrics.py +178 -0
  198. agno/os/routers/metrics/schemas.py +47 -0
  199. agno/os/routers/session/__init__.py +3 -0
  200. agno/os/routers/session/session.py +536 -0
  201. agno/os/schema.py +945 -0
  202. agno/{app/playground → os}/settings.py +7 -15
  203. agno/os/utils.py +270 -0
  204. agno/reasoning/azure_ai_foundry.py +4 -4
  205. agno/reasoning/deepseek.py +4 -4
  206. agno/reasoning/default.py +6 -11
  207. agno/reasoning/groq.py +4 -4
  208. agno/reasoning/helpers.py +4 -6
  209. agno/reasoning/ollama.py +4 -4
  210. agno/reasoning/openai.py +4 -4
  211. agno/run/agent.py +633 -0
  212. agno/run/base.py +53 -77
  213. agno/run/cancel.py +81 -0
  214. agno/run/team.py +243 -96
  215. agno/run/workflow.py +550 -12
  216. agno/session/__init__.py +10 -0
  217. agno/session/agent.py +244 -0
  218. agno/session/summary.py +225 -0
  219. agno/session/team.py +262 -0
  220. agno/{storage/session/v2 → session}/workflow.py +47 -24
  221. agno/team/__init__.py +15 -16
  222. agno/team/team.py +3260 -4824
  223. agno/tools/agentql.py +14 -5
  224. agno/tools/airflow.py +9 -4
  225. agno/tools/api.py +7 -3
  226. agno/tools/apify.py +2 -46
  227. agno/tools/arxiv.py +8 -3
  228. agno/tools/aws_lambda.py +7 -5
  229. agno/tools/aws_ses.py +7 -1
  230. agno/tools/baidusearch.py +4 -1
  231. agno/tools/bitbucket.py +4 -4
  232. agno/tools/brandfetch.py +14 -11
  233. agno/tools/bravesearch.py +4 -1
  234. agno/tools/brightdata.py +43 -23
  235. agno/tools/browserbase.py +13 -4
  236. agno/tools/calcom.py +12 -10
  237. agno/tools/calculator.py +10 -27
  238. agno/tools/cartesia.py +20 -17
  239. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  240. agno/tools/confluence.py +8 -8
  241. agno/tools/crawl4ai.py +7 -1
  242. agno/tools/csv_toolkit.py +9 -8
  243. agno/tools/dalle.py +22 -12
  244. agno/tools/daytona.py +13 -16
  245. agno/tools/decorator.py +6 -3
  246. agno/tools/desi_vocal.py +17 -8
  247. agno/tools/discord.py +11 -8
  248. agno/tools/docker.py +30 -42
  249. agno/tools/duckdb.py +34 -53
  250. agno/tools/duckduckgo.py +8 -7
  251. agno/tools/e2b.py +62 -62
  252. agno/tools/eleven_labs.py +36 -29
  253. agno/tools/email.py +4 -1
  254. agno/tools/evm.py +7 -1
  255. agno/tools/exa.py +19 -14
  256. agno/tools/fal.py +30 -30
  257. agno/tools/file.py +9 -8
  258. agno/tools/financial_datasets.py +25 -44
  259. agno/tools/firecrawl.py +17 -18
  260. agno/tools/function.py +127 -18
  261. agno/tools/giphy.py +23 -11
  262. agno/tools/github.py +48 -126
  263. agno/tools/gmail.py +45 -61
  264. agno/tools/google_bigquery.py +7 -6
  265. agno/tools/google_maps.py +11 -26
  266. agno/tools/googlesearch.py +7 -2
  267. agno/tools/googlesheets.py +21 -17
  268. agno/tools/hackernews.py +9 -5
  269. agno/tools/jina.py +5 -4
  270. agno/tools/jira.py +18 -9
  271. agno/tools/knowledge.py +31 -32
  272. agno/tools/linear.py +18 -33
  273. agno/tools/linkup.py +5 -1
  274. agno/tools/local_file_system.py +8 -5
  275. agno/tools/lumalab.py +32 -20
  276. agno/tools/mcp.py +1 -2
  277. agno/tools/mem0.py +18 -12
  278. agno/tools/memori.py +14 -10
  279. agno/tools/mlx_transcribe.py +3 -2
  280. agno/tools/models/azure_openai.py +33 -15
  281. agno/tools/models/gemini.py +59 -32
  282. agno/tools/models/groq.py +30 -23
  283. agno/tools/models/nebius.py +28 -12
  284. agno/tools/models_labs.py +40 -16
  285. agno/tools/moviepy_video.py +7 -6
  286. agno/tools/neo4j.py +10 -8
  287. agno/tools/newspaper.py +7 -2
  288. agno/tools/newspaper4k.py +8 -3
  289. agno/tools/openai.py +58 -32
  290. agno/tools/openbb.py +12 -11
  291. agno/tools/opencv.py +63 -47
  292. agno/tools/openweather.py +14 -12
  293. agno/tools/pandas.py +11 -3
  294. agno/tools/postgres.py +4 -12
  295. agno/tools/pubmed.py +4 -1
  296. agno/tools/python.py +9 -22
  297. agno/tools/reasoning.py +35 -27
  298. agno/tools/reddit.py +11 -26
  299. agno/tools/replicate.py +55 -42
  300. agno/tools/resend.py +4 -1
  301. agno/tools/scrapegraph.py +15 -14
  302. agno/tools/searxng.py +10 -23
  303. agno/tools/serpapi.py +6 -3
  304. agno/tools/serper.py +13 -4
  305. agno/tools/shell.py +9 -2
  306. agno/tools/slack.py +12 -11
  307. agno/tools/sleep.py +3 -2
  308. agno/tools/spider.py +24 -4
  309. agno/tools/sql.py +7 -6
  310. agno/tools/tavily.py +6 -4
  311. agno/tools/telegram.py +12 -4
  312. agno/tools/todoist.py +11 -31
  313. agno/tools/toolkit.py +1 -1
  314. agno/tools/trafilatura.py +22 -6
  315. agno/tools/trello.py +9 -22
  316. agno/tools/twilio.py +10 -3
  317. agno/tools/user_control_flow.py +6 -1
  318. agno/tools/valyu.py +34 -5
  319. agno/tools/visualization.py +19 -28
  320. agno/tools/webbrowser.py +4 -3
  321. agno/tools/webex.py +11 -7
  322. agno/tools/website.py +15 -46
  323. agno/tools/webtools.py +12 -4
  324. agno/tools/whatsapp.py +5 -9
  325. agno/tools/wikipedia.py +20 -13
  326. agno/tools/x.py +14 -13
  327. agno/tools/yfinance.py +13 -40
  328. agno/tools/youtube.py +26 -20
  329. agno/tools/zendesk.py +7 -2
  330. agno/tools/zep.py +10 -7
  331. agno/tools/zoom.py +10 -9
  332. agno/utils/common.py +1 -19
  333. agno/utils/events.py +100 -123
  334. agno/utils/gemini.py +1 -1
  335. agno/utils/knowledge.py +29 -0
  336. agno/utils/log.py +54 -4
  337. agno/utils/mcp.py +68 -10
  338. agno/utils/media.py +39 -0
  339. agno/utils/message.py +12 -1
  340. agno/utils/models/aws_claude.py +1 -1
  341. agno/utils/models/claude.py +6 -12
  342. agno/utils/models/cohere.py +1 -1
  343. agno/utils/models/mistral.py +8 -7
  344. agno/utils/models/schema_utils.py +3 -3
  345. agno/utils/models/watsonx.py +1 -1
  346. agno/utils/openai.py +1 -1
  347. agno/utils/pprint.py +33 -32
  348. agno/utils/print_response/agent.py +779 -0
  349. agno/utils/print_response/team.py +1669 -0
  350. agno/utils/print_response/workflow.py +1451 -0
  351. agno/utils/prompts.py +14 -14
  352. agno/utils/reasoning.py +87 -0
  353. agno/utils/response.py +42 -42
  354. agno/utils/streamlit.py +481 -0
  355. agno/utils/string.py +8 -22
  356. agno/utils/team.py +50 -0
  357. agno/utils/timer.py +2 -2
  358. agno/vectordb/base.py +33 -21
  359. agno/vectordb/cassandra/cassandra.py +287 -23
  360. agno/vectordb/chroma/chromadb.py +482 -59
  361. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  362. agno/vectordb/couchbase/couchbase.py +309 -29
  363. agno/vectordb/lancedb/lance_db.py +360 -21
  364. agno/vectordb/langchaindb/__init__.py +5 -0
  365. agno/vectordb/langchaindb/langchaindb.py +145 -0
  366. agno/vectordb/lightrag/__init__.py +5 -0
  367. agno/vectordb/lightrag/lightrag.py +374 -0
  368. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  369. agno/vectordb/milvus/milvus.py +242 -32
  370. agno/vectordb/mongodb/mongodb.py +200 -24
  371. agno/vectordb/pgvector/pgvector.py +319 -37
  372. agno/vectordb/pineconedb/pineconedb.py +221 -27
  373. agno/vectordb/qdrant/qdrant.py +334 -14
  374. agno/vectordb/singlestore/singlestore.py +286 -29
  375. agno/vectordb/surrealdb/surrealdb.py +187 -7
  376. agno/vectordb/upstashdb/upstashdb.py +342 -26
  377. agno/vectordb/weaviate/weaviate.py +227 -165
  378. agno/workflow/__init__.py +17 -13
  379. agno/workflow/{v2/condition.py → condition.py} +135 -32
  380. agno/workflow/{v2/loop.py → loop.py} +115 -28
  381. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  382. agno/workflow/{v2/router.py → router.py} +133 -32
  383. agno/workflow/{v2/step.py → step.py} +207 -49
  384. agno/workflow/{v2/steps.py → steps.py} +147 -66
  385. agno/workflow/types.py +482 -0
  386. agno/workflow/workflow.py +2410 -696
  387. agno-2.0.0.dist-info/METADATA +494 -0
  388. agno-2.0.0.dist-info/RECORD +515 -0
  389. agno-2.0.0.dist-info/licenses/LICENSE +201 -0
  390. agno/agent/metrics.py +0 -110
  391. agno/api/app.py +0 -35
  392. agno/api/playground.py +0 -92
  393. agno/api/schemas/app.py +0 -12
  394. agno/api/schemas/playground.py +0 -22
  395. agno/api/schemas/user.py +0 -35
  396. agno/api/schemas/workspace.py +0 -46
  397. agno/api/user.py +0 -160
  398. agno/api/workflows.py +0 -33
  399. agno/api/workspace.py +0 -175
  400. agno/app/agui/__init__.py +0 -3
  401. agno/app/agui/app.py +0 -17
  402. agno/app/agui/sync_router.py +0 -120
  403. agno/app/base.py +0 -186
  404. agno/app/discord/__init__.py +0 -3
  405. agno/app/fastapi/__init__.py +0 -3
  406. agno/app/fastapi/app.py +0 -107
  407. agno/app/fastapi/async_router.py +0 -457
  408. agno/app/fastapi/sync_router.py +0 -448
  409. agno/app/playground/app.py +0 -228
  410. agno/app/playground/async_router.py +0 -1053
  411. agno/app/playground/deploy.py +0 -249
  412. agno/app/playground/operator.py +0 -183
  413. agno/app/playground/schemas.py +0 -223
  414. agno/app/playground/serve.py +0 -55
  415. agno/app/playground/sync_router.py +0 -1045
  416. agno/app/playground/utils.py +0 -46
  417. agno/app/settings.py +0 -15
  418. agno/app/slack/__init__.py +0 -3
  419. agno/app/slack/app.py +0 -19
  420. agno/app/slack/sync_router.py +0 -92
  421. agno/app/utils.py +0 -54
  422. agno/app/whatsapp/__init__.py +0 -3
  423. agno/app/whatsapp/app.py +0 -15
  424. agno/app/whatsapp/sync_router.py +0 -197
  425. agno/cli/auth_server.py +0 -249
  426. agno/cli/config.py +0 -274
  427. agno/cli/console.py +0 -88
  428. agno/cli/credentials.py +0 -23
  429. agno/cli/entrypoint.py +0 -571
  430. agno/cli/operator.py +0 -357
  431. agno/cli/settings.py +0 -96
  432. agno/cli/ws/ws_cli.py +0 -817
  433. agno/constants.py +0 -13
  434. agno/document/__init__.py +0 -5
  435. agno/document/chunking/semantic.py +0 -45
  436. agno/document/chunking/strategy.py +0 -31
  437. agno/document/reader/__init__.py +0 -5
  438. agno/document/reader/base.py +0 -47
  439. agno/document/reader/docx_reader.py +0 -60
  440. agno/document/reader/gcs/pdf_reader.py +0 -44
  441. agno/document/reader/s3/pdf_reader.py +0 -59
  442. agno/document/reader/s3/text_reader.py +0 -63
  443. agno/document/reader/url_reader.py +0 -59
  444. agno/document/reader/youtube_reader.py +0 -58
  445. agno/embedder/__init__.py +0 -5
  446. agno/embedder/langdb.py +0 -80
  447. agno/embedder/mistral.py +0 -82
  448. agno/embedder/openai.py +0 -78
  449. agno/file/__init__.py +0 -5
  450. agno/file/file.py +0 -16
  451. agno/file/local/csv.py +0 -32
  452. agno/file/local/txt.py +0 -19
  453. agno/infra/app.py +0 -240
  454. agno/infra/base.py +0 -144
  455. agno/infra/context.py +0 -20
  456. agno/infra/db_app.py +0 -52
  457. agno/infra/resource.py +0 -205
  458. agno/infra/resources.py +0 -55
  459. agno/knowledge/agent.py +0 -702
  460. agno/knowledge/arxiv.py +0 -33
  461. agno/knowledge/combined.py +0 -36
  462. agno/knowledge/csv.py +0 -144
  463. agno/knowledge/csv_url.py +0 -124
  464. agno/knowledge/document.py +0 -223
  465. agno/knowledge/docx.py +0 -137
  466. agno/knowledge/firecrawl.py +0 -34
  467. agno/knowledge/gcs/__init__.py +0 -0
  468. agno/knowledge/gcs/base.py +0 -39
  469. agno/knowledge/gcs/pdf.py +0 -125
  470. agno/knowledge/json.py +0 -137
  471. agno/knowledge/langchain.py +0 -71
  472. agno/knowledge/light_rag.py +0 -273
  473. agno/knowledge/llamaindex.py +0 -66
  474. agno/knowledge/markdown.py +0 -154
  475. agno/knowledge/pdf.py +0 -164
  476. agno/knowledge/pdf_bytes.py +0 -42
  477. agno/knowledge/pdf_url.py +0 -148
  478. agno/knowledge/s3/__init__.py +0 -0
  479. agno/knowledge/s3/base.py +0 -64
  480. agno/knowledge/s3/pdf.py +0 -33
  481. agno/knowledge/s3/text.py +0 -34
  482. agno/knowledge/text.py +0 -141
  483. agno/knowledge/url.py +0 -46
  484. agno/knowledge/website.py +0 -179
  485. agno/knowledge/wikipedia.py +0 -32
  486. agno/knowledge/youtube.py +0 -35
  487. agno/memory/agent.py +0 -423
  488. agno/memory/classifier.py +0 -104
  489. agno/memory/db/__init__.py +0 -5
  490. agno/memory/db/base.py +0 -42
  491. agno/memory/db/mongodb.py +0 -189
  492. agno/memory/db/postgres.py +0 -203
  493. agno/memory/db/sqlite.py +0 -193
  494. agno/memory/memory.py +0 -22
  495. agno/memory/row.py +0 -36
  496. agno/memory/summarizer.py +0 -201
  497. agno/memory/summary.py +0 -19
  498. agno/memory/team.py +0 -415
  499. agno/memory/v2/__init__.py +0 -2
  500. agno/memory/v2/db/__init__.py +0 -1
  501. agno/memory/v2/db/base.py +0 -42
  502. agno/memory/v2/db/firestore.py +0 -339
  503. agno/memory/v2/db/mongodb.py +0 -196
  504. agno/memory/v2/db/postgres.py +0 -214
  505. agno/memory/v2/db/redis.py +0 -187
  506. agno/memory/v2/db/schema.py +0 -54
  507. agno/memory/v2/db/sqlite.py +0 -209
  508. agno/memory/v2/manager.py +0 -437
  509. agno/memory/v2/memory.py +0 -1097
  510. agno/memory/v2/schema.py +0 -55
  511. agno/memory/v2/summarizer.py +0 -215
  512. agno/memory/workflow.py +0 -38
  513. agno/models/ollama/tools.py +0 -430
  514. agno/models/qwen/__init__.py +0 -5
  515. agno/playground/__init__.py +0 -10
  516. agno/playground/deploy.py +0 -3
  517. agno/playground/playground.py +0 -3
  518. agno/playground/serve.py +0 -3
  519. agno/playground/settings.py +0 -3
  520. agno/reranker/__init__.py +0 -0
  521. agno/run/response.py +0 -467
  522. agno/run/v2/__init__.py +0 -0
  523. agno/run/v2/workflow.py +0 -567
  524. agno/storage/__init__.py +0 -0
  525. agno/storage/agent/__init__.py +0 -0
  526. agno/storage/agent/dynamodb.py +0 -1
  527. agno/storage/agent/json.py +0 -1
  528. agno/storage/agent/mongodb.py +0 -1
  529. agno/storage/agent/postgres.py +0 -1
  530. agno/storage/agent/singlestore.py +0 -1
  531. agno/storage/agent/sqlite.py +0 -1
  532. agno/storage/agent/yaml.py +0 -1
  533. agno/storage/base.py +0 -60
  534. agno/storage/dynamodb.py +0 -673
  535. agno/storage/firestore.py +0 -297
  536. agno/storage/gcs_json.py +0 -261
  537. agno/storage/in_memory.py +0 -234
  538. agno/storage/json.py +0 -237
  539. agno/storage/mongodb.py +0 -328
  540. agno/storage/mysql.py +0 -685
  541. agno/storage/postgres.py +0 -682
  542. agno/storage/redis.py +0 -336
  543. agno/storage/session/__init__.py +0 -16
  544. agno/storage/session/agent.py +0 -64
  545. agno/storage/session/team.py +0 -63
  546. agno/storage/session/v2/__init__.py +0 -5
  547. agno/storage/session/workflow.py +0 -61
  548. agno/storage/singlestore.py +0 -606
  549. agno/storage/sqlite.py +0 -646
  550. agno/storage/workflow/__init__.py +0 -0
  551. agno/storage/workflow/mongodb.py +0 -1
  552. agno/storage/workflow/postgres.py +0 -1
  553. agno/storage/workflow/sqlite.py +0 -1
  554. agno/storage/yaml.py +0 -241
  555. agno/tools/thinking.py +0 -73
  556. agno/utils/defaults.py +0 -57
  557. agno/utils/filesystem.py +0 -39
  558. agno/utils/git.py +0 -52
  559. agno/utils/json_io.py +0 -30
  560. agno/utils/load_env.py +0 -19
  561. agno/utils/py_io.py +0 -19
  562. agno/utils/pyproject.py +0 -18
  563. agno/utils/resource_filter.py +0 -31
  564. agno/workflow/v2/__init__.py +0 -21
  565. agno/workflow/v2/types.py +0 -357
  566. agno/workflow/v2/workflow.py +0 -3313
  567. agno/workspace/__init__.py +0 -0
  568. agno/workspace/config.py +0 -325
  569. agno/workspace/enums.py +0 -6
  570. agno/workspace/helpers.py +0 -52
  571. agno/workspace/operator.py +0 -757
  572. agno/workspace/settings.py +0 -158
  573. agno-1.8.2.dist-info/METADATA +0 -982
  574. agno-1.8.2.dist-info/RECORD +0 -566
  575. agno-1.8.2.dist-info/entry_points.txt +0 -3
  576. agno-1.8.2.dist-info/licenses/LICENSE +0 -375
  577. /agno/{app → db/migrations}/__init__.py +0 -0
  578. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  579. /agno/{cli → integrations}/__init__.py +0 -0
  580. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  581. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  582. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  583. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  584. /agno/{app → os/interfaces}/slack/security.py +0 -0
  585. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  586. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  587. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  588. {agno-1.8.2.dist-info → agno-2.0.0.dist-info}/WHEEL +0 -0
  589. {agno-1.8.2.dist-info → agno-2.0.0.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,15 @@
1
1
  from dataclasses import dataclass
2
2
  from os import getenv
3
- from typing import Any, Dict, Iterator, List, Optional, Type, Union
3
+ from typing import Any, AsyncIterator, Dict, Iterator, List, Optional, Type, Union
4
4
 
5
5
  from pydantic import BaseModel
6
6
 
7
7
  from agno.exceptions import ModelProviderError
8
8
  from agno.models.base import Model
9
9
  from agno.models.message import Message
10
+ from agno.models.metrics import Metrics
10
11
  from agno.models.response import ModelResponse
12
+ from agno.run.agent import RunOutput
11
13
  from agno.utils.log import log_debug, log_error
12
14
  from agno.utils.models.mistral import format_messages
13
15
 
@@ -24,7 +26,9 @@ try:
24
26
  ToolMessage,
25
27
  UserMessage,
26
28
  )
27
- from mistralai.models.chatcompletionresponse import ChatCompletionResponse
29
+ from mistralai.models.chatcompletionresponse import (
30
+ ChatCompletionResponse,
31
+ )
28
32
  from mistralai.models.deltamessage import DeltaMessage
29
33
  from mistralai.types.basemodel import Unset
30
34
 
@@ -165,10 +169,12 @@ class MistralChat(Model):
165
169
  def invoke(
166
170
  self,
167
171
  messages: List[Message],
172
+ assistant_message: Message,
168
173
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
169
174
  tools: Optional[List[Dict[str, Any]]] = None,
170
175
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
171
- ) -> Union[ChatCompletionResponse, ParsedChatCompletionResponse]:
176
+ run_response: Optional[RunOutput] = None,
177
+ ) -> ModelResponse:
172
178
  """
173
179
  Send a chat completion request to the Mistral model.
174
180
  """
@@ -180,6 +186,11 @@ class MistralChat(Model):
180
186
  and isinstance(response_format, type)
181
187
  and issubclass(response_format, BaseModel)
182
188
  ):
189
+ if run_response and run_response.metrics:
190
+ run_response.metrics.set_time_to_first_token()
191
+
192
+ assistant_message.metrics.start_timer()
193
+
183
194
  response = self.get_client().chat.complete(
184
195
  model=self.id,
185
196
  messages=mistral_messages,
@@ -187,12 +198,21 @@ class MistralChat(Model):
187
198
  **self.get_request_params(tools=tools, tool_choice=tool_choice),
188
199
  )
189
200
  else:
201
+ if run_response and run_response.metrics:
202
+ run_response.metrics.set_time_to_first_token()
203
+
204
+ assistant_message.metrics.start_timer()
190
205
  response = self.get_client().chat.complete(
191
206
  model=self.id,
192
207
  messages=mistral_messages,
193
208
  **self.get_request_params(tools=tools, tool_choice=tool_choice),
194
209
  )
195
- return response
210
+
211
+ assistant_message.metrics.stop_timer()
212
+
213
+ model_response = self._parse_provider_response(response, response_format=response_format)
214
+
215
+ return model_response
196
216
 
197
217
  except HTTPValidationError as e:
198
218
  log_error(f"HTTPValidationError from Mistral: {e}")
@@ -204,21 +224,32 @@ class MistralChat(Model):
204
224
  def invoke_stream(
205
225
  self,
206
226
  messages: List[Message],
227
+ assistant_message: Message,
207
228
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
208
229
  tools: Optional[List[Dict[str, Any]]] = None,
209
230
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
210
- ) -> Iterator[Any]:
231
+ run_response: Optional[RunOutput] = None,
232
+ ) -> Iterator[ModelResponse]:
211
233
  """
212
234
  Stream the response from the Mistral model.
213
235
  """
214
236
  mistral_messages = format_messages(messages)
237
+
238
+ if run_response and run_response.metrics:
239
+ run_response.metrics.set_time_to_first_token()
240
+
241
+ assistant_message.metrics.start_timer()
242
+
215
243
  try:
216
- stream = self.get_client().chat.stream(
244
+ for chunk in self.get_client().chat.stream(
217
245
  model=self.id,
218
246
  messages=mistral_messages,
219
247
  **self.get_request_params(tools=tools, tool_choice=tool_choice),
220
- )
221
- return stream
248
+ ):
249
+ yield self._parse_provider_response_delta(chunk)
250
+
251
+ assistant_message.metrics.stop_timer()
252
+
222
253
  except HTTPValidationError as e:
223
254
  log_error(f"HTTPValidationError from Mistral: {e}")
224
255
  raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
@@ -229,10 +260,12 @@ class MistralChat(Model):
229
260
  async def ainvoke(
230
261
  self,
231
262
  messages: List[Message],
263
+ assistant_message: Message,
232
264
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
233
265
  tools: Optional[List[Dict[str, Any]]] = None,
234
266
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
235
- ) -> Union[ChatCompletionResponse, ParsedChatCompletionResponse]:
267
+ run_response: Optional[RunOutput] = None,
268
+ ) -> ModelResponse:
236
269
  """
237
270
  Send an asynchronous chat completion request to the Mistral API.
238
271
  """
@@ -244,6 +277,9 @@ class MistralChat(Model):
244
277
  and isinstance(response_format, type)
245
278
  and issubclass(response_format, BaseModel)
246
279
  ):
280
+ if run_response and run_response.metrics:
281
+ run_response.metrics.set_time_to_first_token()
282
+ assistant_message.metrics.start_timer()
247
283
  response = await self.get_client().chat.complete_async(
248
284
  model=self.id,
249
285
  messages=mistral_messages,
@@ -251,12 +287,20 @@ class MistralChat(Model):
251
287
  **self.get_request_params(tools=tools, tool_choice=tool_choice),
252
288
  )
253
289
  else:
290
+ if run_response and run_response.metrics:
291
+ run_response.metrics.set_time_to_first_token()
292
+ assistant_message.metrics.start_timer()
254
293
  response = await self.get_client().chat.complete_async(
255
294
  model=self.id,
256
295
  messages=mistral_messages,
257
296
  **self.get_request_params(tools=tools, tool_choice=tool_choice),
258
297
  )
259
- return response
298
+
299
+ assistant_message.metrics.stop_timer()
300
+
301
+ model_response = self._parse_provider_response(response, response_format=response_format)
302
+
303
+ return model_response
260
304
  except HTTPValidationError as e:
261
305
  log_error(f"HTTPValidationError from Mistral: {e}")
262
306
  raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
@@ -267,24 +311,31 @@ class MistralChat(Model):
267
311
  async def ainvoke_stream(
268
312
  self,
269
313
  messages: List[Message],
314
+ assistant_message: Message,
270
315
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
271
316
  tools: Optional[List[Dict[str, Any]]] = None,
272
317
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
273
- ) -> Any:
318
+ run_response: Optional[RunOutput] = None,
319
+ ) -> AsyncIterator[ModelResponse]:
274
320
  """
275
321
  Stream an asynchronous response from the Mistral API.
276
322
  """
277
323
  mistral_messages = format_messages(messages)
278
324
  try:
279
- stream = await self.get_client().chat.stream_async(
325
+ if run_response and run_response.metrics:
326
+ run_response.metrics.set_time_to_first_token()
327
+
328
+ assistant_message.metrics.start_timer()
329
+
330
+ async for chunk in await self.get_client().chat.stream_async(
280
331
  model=self.id,
281
332
  messages=mistral_messages,
282
333
  **self.get_request_params(tools=tools, tool_choice=tool_choice),
283
- )
284
- if stream is None:
285
- raise ValueError("Chat stream returned None")
286
- async for chunk in stream:
287
- yield chunk
334
+ ):
335
+ yield self._parse_provider_response_delta(chunk)
336
+
337
+ assistant_message.metrics.stop_timer()
338
+
288
339
  except HTTPValidationError as e:
289
340
  log_error(f"HTTPValidationError from Mistral: {e}")
290
341
  raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
@@ -292,7 +343,7 @@ class MistralChat(Model):
292
343
  log_error(f"SDKError from Mistral: {e}")
293
344
  raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
294
345
 
295
- def parse_provider_response(self, response: ChatCompletionResponse, **kwargs) -> ModelResponse:
346
+ def _parse_provider_response(self, response: ChatCompletionResponse, **kwargs) -> ModelResponse:
296
347
  """
297
348
  Parse the response from the Mistral model.
298
349
 
@@ -322,11 +373,11 @@ class MistralChat(Model):
322
373
  )
323
374
 
324
375
  if response.usage is not None:
325
- model_response.response_usage = response.usage
376
+ model_response.response_usage = self._get_metrics(response.usage)
326
377
 
327
378
  return model_response
328
379
 
329
- def parse_provider_response_delta(self, response_delta: CompletionEvent) -> Optional[ModelResponse]:
380
+ def _parse_provider_response_delta(self, response_delta: CompletionEvent) -> ModelResponse:
330
381
  """
331
382
  Parse the response delta from the Mistral model.
332
383
  """
@@ -358,6 +409,24 @@ class MistralChat(Model):
358
409
  )
359
410
 
360
411
  if response_delta.data.usage is not None:
361
- model_response.response_usage = response_delta.data.usage
412
+ model_response.response_usage = self._get_metrics(response_delta.data.usage)
362
413
 
363
414
  return model_response
415
+
416
+ def _get_metrics(self, response_usage: Any) -> Metrics:
417
+ """
418
+ Parse the given Mistral usage into an Agno Metrics object.
419
+
420
+ Args:
421
+ response_usage: Usage data from Mistral
422
+
423
+ Returns:
424
+ Metrics: Parsed metrics data
425
+ """
426
+ metrics = Metrics()
427
+
428
+ metrics.input_tokens = response_usage.prompt_tokens or 0
429
+ metrics.output_tokens = response_usage.completion_tokens or 0
430
+ metrics.total_tokens = metrics.input_tokens + metrics.output_tokens
431
+
432
+ return metrics
@@ -1,7 +1,5 @@
1
1
  from agno.models.ollama.chat import Ollama
2
- from agno.models.ollama.tools import OllamaTools
3
2
 
4
3
  __all__ = [
5
4
  "Ollama",
6
- "OllamaTools",
7
5
  ]
@@ -1,11 +1,13 @@
1
1
  import json
2
2
  from dataclasses import dataclass
3
- from typing import Any, Dict, Iterator, List, Mapping, Optional, Type, Union
3
+ from typing import Any, AsyncIterator, Dict, Iterator, List, Optional, Type, Union
4
4
 
5
5
  from pydantic import BaseModel
6
6
 
7
+ from agno.agent import RunOutput
7
8
  from agno.models.base import Model
8
9
  from agno.models.message import Message
10
+ from agno.models.metrics import Metrics
9
11
  from agno.models.response import ModelResponse
10
12
  from agno.utils.log import log_debug, log_warning
11
13
 
@@ -147,7 +149,7 @@ class Ollama(Model):
147
149
  message_images = []
148
150
  for image in message.images:
149
151
  if image.url is not None:
150
- message_images.append(image.image_url_content)
152
+ message_images.append(image.get_content_bytes())
151
153
  if image.filepath is not None:
152
154
  message_images.append(image.filepath) # type: ignore
153
155
  if image.content is not None and isinstance(image.content, bytes):
@@ -182,86 +184,124 @@ class Ollama(Model):
182
184
  def invoke(
183
185
  self,
184
186
  messages: List[Message],
187
+ assistant_message: Message,
185
188
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
186
189
  tools: Optional[List[Dict[str, Any]]] = None,
187
190
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
188
- ) -> Mapping[str, Any]:
191
+ run_response: Optional[RunOutput] = None,
192
+ ) -> ModelResponse:
189
193
  """
190
194
  Send a chat request to the Ollama API.
191
195
  """
192
196
  request_kwargs = self._prepare_request_kwargs_for_invoke(response_format=response_format, tools=tools)
193
197
 
194
- return self.get_client().chat(
198
+ if run_response and run_response.metrics:
199
+ run_response.metrics.set_time_to_first_token()
200
+
201
+ assistant_message.metrics.start_timer()
202
+
203
+ provider_response = self.get_client().chat(
195
204
  model=self.id.strip(),
196
205
  messages=[self._format_message(m) for m in messages], # type: ignore
197
206
  **request_kwargs,
198
207
  ) # type: ignore
199
208
 
209
+ assistant_message.metrics.stop_timer()
210
+
211
+ model_response = self._parse_provider_response(provider_response) # type: ignore
212
+ return model_response
213
+
200
214
  async def ainvoke(
201
215
  self,
202
216
  messages: List[Message],
217
+ assistant_message: Message,
203
218
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
204
219
  tools: Optional[List[Dict[str, Any]]] = None,
205
220
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
206
- ) -> Mapping[str, Any]:
221
+ run_response: Optional[RunOutput] = None,
222
+ ) -> ModelResponse:
207
223
  """
208
224
  Sends an asynchronous chat request to the Ollama API.
209
225
  """
210
226
  request_kwargs = self._prepare_request_kwargs_for_invoke(response_format=response_format, tools=tools)
211
227
 
212
- return await self.get_async_client().chat(
228
+ if run_response and run_response.metrics:
229
+ run_response.metrics.set_time_to_first_token()
230
+
231
+ assistant_message.metrics.start_timer()
232
+
233
+ provider_response = await self.get_async_client().chat(
213
234
  model=self.id.strip(),
214
235
  messages=[self._format_message(m) for m in messages], # type: ignore
215
236
  **request_kwargs,
216
237
  ) # type: ignore
217
238
 
239
+ assistant_message.metrics.stop_timer()
240
+
241
+ model_response = self._parse_provider_response(provider_response) # type: ignore
242
+ return model_response
243
+
218
244
  def invoke_stream(
219
245
  self,
220
246
  messages: List[Message],
247
+ assistant_message: Message,
221
248
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
222
249
  tools: Optional[List[Dict[str, Any]]] = None,
223
250
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
224
- ) -> Iterator[Mapping[str, Any]]:
251
+ run_response: Optional[RunOutput] = None,
252
+ ) -> Iterator[ModelResponse]:
225
253
  """
226
254
  Sends a streaming chat request to the Ollama API.
227
255
  """
228
- yield from self.get_client().chat(
256
+ if run_response and run_response.metrics:
257
+ run_response.metrics.set_time_to_first_token()
258
+
259
+ assistant_message.metrics.start_timer()
260
+
261
+ for chunk in self.get_client().chat(
229
262
  model=self.id,
230
263
  messages=[self._format_message(m) for m in messages], # type: ignore
231
264
  stream=True,
232
265
  **self.get_request_params(tools=tools),
233
- ) # type: ignore
266
+ ):
267
+ yield self._parse_provider_response_delta(chunk)
268
+
269
+ assistant_message.metrics.stop_timer()
234
270
 
235
271
  async def ainvoke_stream(
236
272
  self,
237
273
  messages: List[Message],
274
+ assistant_message: Message,
238
275
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
239
276
  tools: Optional[List[Dict[str, Any]]] = None,
240
277
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
241
- ) -> Any:
278
+ run_response: Optional[RunOutput] = None,
279
+ ) -> AsyncIterator[ModelResponse]:
242
280
  """
243
281
  Sends an asynchronous streaming chat completion request to the Ollama API.
244
282
  """
245
- async_stream = await self.get_async_client().chat(
283
+ if run_response and run_response.metrics:
284
+ run_response.metrics.set_time_to_first_token()
285
+
286
+ assistant_message.metrics.start_timer()
287
+
288
+ async for chunk in await self.get_async_client().chat(
246
289
  model=self.id.strip(),
247
290
  messages=[self._format_message(m) for m in messages], # type: ignore
248
291
  stream=True,
249
292
  **self.get_request_params(tools=tools),
250
- )
251
- async for chunk in async_stream: # type: ignore
252
- yield chunk
293
+ ):
294
+ yield self._parse_provider_response_delta(chunk)
253
295
 
254
- def parse_provider_response(
255
- self,
256
- response: ChatResponse,
257
- response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
258
- ) -> ModelResponse:
296
+ assistant_message.metrics.stop_timer()
297
+
298
+ def _parse_provider_response(self, response: dict) -> ModelResponse:
259
299
  """
260
300
  Parse the provider response.
261
301
  """
262
302
  model_response = ModelResponse()
263
303
  # Get response message
264
- response_message: OllamaMessage = response.get("message")
304
+ response_message: OllamaMessage = response.get("message") # type: ignore
265
305
 
266
306
  if response_message.get("role") is not None:
267
307
  model_response.role = response_message.get("role")
@@ -272,7 +312,7 @@ class Ollama(Model):
272
312
  if response_message.get("tool_calls") is not None:
273
313
  if model_response.tool_calls is None:
274
314
  model_response.tool_calls = []
275
- for block in response_message.get("tool_calls"):
315
+ for block in response_message.get("tool_calls", []):
276
316
  tool_call = block.get("function")
277
317
  tool_name = tool_call.get("name")
278
318
  tool_args = tool_call.get("arguments")
@@ -288,33 +328,23 @@ class Ollama(Model):
288
328
 
289
329
  # Get response usage
290
330
  if response.get("done"):
291
- model_response.response_usage = {
292
- "input_tokens": response.get("prompt_eval_count", 0),
293
- "output_tokens": response.get("eval_count", 0),
294
- "total_tokens": response.get("prompt_eval_count", 0) + response.get("eval_count", 0),
295
- "additional_metrics": {
296
- "total_duration": response.get("total_duration", 0),
297
- "load_duration": response.get("load_duration", 0),
298
- "prompt_eval_duration": response.get("prompt_eval_duration", 0),
299
- "eval_duration": response.get("eval_duration", 0),
300
- },
301
- }
331
+ model_response.response_usage = self._get_metrics(response)
302
332
 
303
333
  return model_response
304
334
 
305
- def parse_provider_response_delta(self, response_delta: ChatResponse) -> ModelResponse:
335
+ def _parse_provider_response_delta(self, response: ChatResponse) -> ModelResponse:
306
336
  """
307
337
  Parse the provider response delta.
308
338
 
309
339
  Args:
310
- response_delta (ChatResponse): The response from the provider.
340
+ response (ChatResponse): The response from the provider.
311
341
 
312
342
  Returns:
313
343
  Iterator[ModelResponse]: An iterator of the model response.
314
344
  """
315
345
  model_response = ModelResponse()
316
346
 
317
- response_message = response_delta.get("message")
347
+ response_message = response.get("message")
318
348
 
319
349
  if response_message is not None:
320
350
  content_delta = response_message.get("content")
@@ -333,17 +363,25 @@ class Ollama(Model):
333
363
  }
334
364
  model_response.tool_calls.append({"type": "function", "function": function_def})
335
365
 
336
- if response_delta.get("done"):
337
- model_response.response_usage = {
338
- "input_tokens": response_delta.get("prompt_eval_count", 0),
339
- "output_tokens": response_delta.get("eval_count", 0),
340
- "total_tokens": response_delta.get("prompt_eval_count", 0) + response_delta.get("eval_count", 0),
341
- "additional_metrics": {
342
- "total_duration": response_delta.get("total_duration", 0),
343
- "load_duration": response_delta.get("load_duration", 0),
344
- "prompt_eval_duration": response_delta.get("prompt_eval_duration", 0),
345
- "eval_duration": response_delta.get("eval_duration", 0),
346
- },
347
- }
366
+ if response.get("done"):
367
+ model_response.response_usage = self._get_metrics(response)
348
368
 
349
369
  return model_response
370
+
371
+ def _get_metrics(self, response: Union[dict, ChatResponse]) -> Metrics:
372
+ """
373
+ Parse the given Ollama usage into an Agno Metrics object.
374
+
375
+ Args:
376
+ response: The response from the provider.
377
+
378
+ Returns:
379
+ Metrics: Parsed metrics data
380
+ """
381
+ metrics = Metrics()
382
+
383
+ metrics.input_tokens = response.get("prompt_eval_count", 0)
384
+ metrics.output_tokens = response.get("eval_count", 0)
385
+ metrics.total_tokens = metrics.input_tokens + metrics.output_tokens
386
+
387
+ return metrics