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