agno 1.8.1__py3-none-any.whl → 2.0.0rc1__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 (583) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +3181 -4169
  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 +1411 -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 +142 -43
  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 +1515 -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 +68 -15
  115. agno/knowledge/reader/docx_reader.py +83 -0
  116. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  117. agno/knowledge/reader/gcs_reader.py +67 -0
  118. agno/{document → knowledge}/reader/json_reader.py +30 -9
  119. agno/{document → knowledge}/reader/markdown_reader.py +36 -9
  120. agno/{document → knowledge}/reader/pdf_reader.py +79 -21
  121. agno/knowledge/reader/reader_factory.py +275 -0
  122. agno/knowledge/reader/s3_reader.py +171 -0
  123. agno/{document → knowledge}/reader/text_reader.py +31 -10
  124. agno/knowledge/reader/url_reader.py +84 -0
  125. agno/knowledge/reader/web_search_reader.py +389 -0
  126. agno/{document → knowledge}/reader/website_reader.py +37 -10
  127. agno/knowledge/reader/wikipedia_reader.py +59 -0
  128. agno/knowledge/reader/youtube_reader.py +78 -0
  129. agno/knowledge/remote_content/remote_content.py +88 -0
  130. agno/{reranker → knowledge/reranker}/base.py +1 -1
  131. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  132. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  133. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  134. agno/knowledge/types.py +30 -0
  135. agno/knowledge/utils.py +169 -0
  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 +107 -175
  142. agno/models/aws/claude.py +64 -18
  143. agno/models/azure/ai_foundry.py +73 -23
  144. agno/models/base.py +347 -287
  145. agno/models/cerebras/cerebras.py +84 -27
  146. agno/models/cohere/chat.py +106 -98
  147. agno/models/google/gemini.py +100 -42
  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 +45 -150
  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 +84 -46
  158. agno/models/openai/chat.py +121 -23
  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 +14 -8
  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 +489 -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 +255 -0
  185. agno/os/router.py +869 -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 +208 -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 +436 -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 +188 -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 +60 -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 +168 -0
  202. agno/os/schema.py +892 -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/{response.py → agent.py} +231 -74
  213. agno/run/base.py +44 -58
  214. agno/run/cancel.py +81 -0
  215. agno/run/team.py +133 -77
  216. agno/run/workflow.py +537 -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 +2960 -4252
  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 +42 -22
  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 +18 -13
  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 +18 -11
  245. agno/tools/daytona.py +13 -16
  246. agno/tools/decorator.py +6 -3
  247. agno/tools/desi_vocal.py +16 -7
  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 +61 -61
  253. agno/tools/eleven_labs.py +35 -28
  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 +29 -29
  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 +22 -10
  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 +31 -19
  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 +32 -14
  281. agno/tools/models/gemini.py +58 -31
  282. agno/tools/models/groq.py +29 -20
  283. agno/tools/models/nebius.py +27 -11
  284. agno/tools/models_labs.py +39 -15
  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 +57 -26
  290. agno/tools/openbb.py +12 -11
  291. agno/tools/opencv.py +62 -46
  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 +54 -41
  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 +95 -118
  334. agno/utils/gemini.py +31 -1
  335. agno/utils/knowledge.py +29 -0
  336. agno/utils/log.py +2 -2
  337. agno/utils/mcp.py +11 -5
  338. agno/utils/media.py +39 -0
  339. agno/utils/message.py +12 -1
  340. agno/utils/models/claude.py +55 -4
  341. agno/utils/models/mistral.py +8 -7
  342. agno/utils/models/schema_utils.py +3 -3
  343. agno/utils/pprint.py +33 -32
  344. agno/utils/print_response/agent.py +779 -0
  345. agno/utils/print_response/team.py +1565 -0
  346. agno/utils/print_response/workflow.py +1451 -0
  347. agno/utils/prompts.py +14 -14
  348. agno/utils/reasoning.py +87 -0
  349. agno/utils/response.py +42 -42
  350. agno/utils/streamlit.py +454 -0
  351. agno/utils/string.py +8 -22
  352. agno/utils/team.py +50 -0
  353. agno/utils/timer.py +2 -2
  354. agno/vectordb/base.py +33 -21
  355. agno/vectordb/cassandra/cassandra.py +287 -23
  356. agno/vectordb/chroma/chromadb.py +482 -59
  357. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  358. agno/vectordb/couchbase/couchbase.py +309 -29
  359. agno/vectordb/lancedb/lance_db.py +360 -21
  360. agno/vectordb/langchaindb/__init__.py +5 -0
  361. agno/vectordb/langchaindb/langchaindb.py +145 -0
  362. agno/vectordb/lightrag/__init__.py +5 -0
  363. agno/vectordb/lightrag/lightrag.py +374 -0
  364. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  365. agno/vectordb/milvus/milvus.py +242 -32
  366. agno/vectordb/mongodb/mongodb.py +200 -24
  367. agno/vectordb/pgvector/pgvector.py +319 -37
  368. agno/vectordb/pineconedb/pineconedb.py +221 -27
  369. agno/vectordb/qdrant/qdrant.py +334 -14
  370. agno/vectordb/singlestore/singlestore.py +286 -29
  371. agno/vectordb/surrealdb/surrealdb.py +187 -7
  372. agno/vectordb/upstashdb/upstashdb.py +342 -26
  373. agno/vectordb/weaviate/weaviate.py +227 -165
  374. agno/workflow/__init__.py +17 -13
  375. agno/workflow/{v2/condition.py → condition.py} +135 -32
  376. agno/workflow/{v2/loop.py → loop.py} +115 -28
  377. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  378. agno/workflow/{v2/router.py → router.py} +133 -32
  379. agno/workflow/{v2/step.py → step.py} +200 -42
  380. agno/workflow/{v2/steps.py → steps.py} +147 -66
  381. agno/workflow/types.py +482 -0
  382. agno/workflow/workflow.py +2401 -696
  383. agno-2.0.0rc1.dist-info/METADATA +355 -0
  384. agno-2.0.0rc1.dist-info/RECORD +516 -0
  385. agno/agent/metrics.py +0 -107
  386. agno/api/app.py +0 -35
  387. agno/api/playground.py +0 -92
  388. agno/api/schemas/app.py +0 -12
  389. agno/api/schemas/playground.py +0 -22
  390. agno/api/schemas/user.py +0 -35
  391. agno/api/schemas/workspace.py +0 -46
  392. agno/api/user.py +0 -160
  393. agno/api/workflows.py +0 -33
  394. agno/api/workspace.py +0 -175
  395. agno/app/agui/__init__.py +0 -3
  396. agno/app/agui/app.py +0 -17
  397. agno/app/agui/sync_router.py +0 -120
  398. agno/app/base.py +0 -186
  399. agno/app/discord/__init__.py +0 -3
  400. agno/app/fastapi/__init__.py +0 -3
  401. agno/app/fastapi/app.py +0 -107
  402. agno/app/fastapi/async_router.py +0 -457
  403. agno/app/fastapi/sync_router.py +0 -448
  404. agno/app/playground/app.py +0 -228
  405. agno/app/playground/async_router.py +0 -1050
  406. agno/app/playground/deploy.py +0 -249
  407. agno/app/playground/operator.py +0 -183
  408. agno/app/playground/schemas.py +0 -220
  409. agno/app/playground/serve.py +0 -55
  410. agno/app/playground/sync_router.py +0 -1042
  411. agno/app/playground/utils.py +0 -46
  412. agno/app/settings.py +0 -15
  413. agno/app/slack/__init__.py +0 -3
  414. agno/app/slack/app.py +0 -19
  415. agno/app/slack/sync_router.py +0 -92
  416. agno/app/utils.py +0 -54
  417. agno/app/whatsapp/__init__.py +0 -3
  418. agno/app/whatsapp/app.py +0 -15
  419. agno/app/whatsapp/sync_router.py +0 -197
  420. agno/cli/auth_server.py +0 -249
  421. agno/cli/config.py +0 -274
  422. agno/cli/console.py +0 -88
  423. agno/cli/credentials.py +0 -23
  424. agno/cli/entrypoint.py +0 -571
  425. agno/cli/operator.py +0 -357
  426. agno/cli/settings.py +0 -96
  427. agno/cli/ws/ws_cli.py +0 -817
  428. agno/constants.py +0 -13
  429. agno/document/__init__.py +0 -5
  430. agno/document/chunking/semantic.py +0 -45
  431. agno/document/chunking/strategy.py +0 -31
  432. agno/document/reader/__init__.py +0 -5
  433. agno/document/reader/base.py +0 -47
  434. agno/document/reader/docx_reader.py +0 -60
  435. agno/document/reader/gcs/pdf_reader.py +0 -44
  436. agno/document/reader/s3/pdf_reader.py +0 -59
  437. agno/document/reader/s3/text_reader.py +0 -63
  438. agno/document/reader/url_reader.py +0 -59
  439. agno/document/reader/youtube_reader.py +0 -58
  440. agno/embedder/__init__.py +0 -5
  441. agno/embedder/langdb.py +0 -80
  442. agno/embedder/mistral.py +0 -82
  443. agno/embedder/openai.py +0 -78
  444. agno/file/__init__.py +0 -5
  445. agno/file/file.py +0 -16
  446. agno/file/local/csv.py +0 -32
  447. agno/file/local/txt.py +0 -19
  448. agno/infra/app.py +0 -240
  449. agno/infra/base.py +0 -144
  450. agno/infra/context.py +0 -20
  451. agno/infra/db_app.py +0 -52
  452. agno/infra/resource.py +0 -205
  453. agno/infra/resources.py +0 -55
  454. agno/knowledge/agent.py +0 -702
  455. agno/knowledge/arxiv.py +0 -33
  456. agno/knowledge/combined.py +0 -36
  457. agno/knowledge/csv.py +0 -144
  458. agno/knowledge/csv_url.py +0 -124
  459. agno/knowledge/document.py +0 -223
  460. agno/knowledge/docx.py +0 -137
  461. agno/knowledge/firecrawl.py +0 -34
  462. agno/knowledge/gcs/__init__.py +0 -0
  463. agno/knowledge/gcs/base.py +0 -39
  464. agno/knowledge/gcs/pdf.py +0 -125
  465. agno/knowledge/json.py +0 -137
  466. agno/knowledge/langchain.py +0 -71
  467. agno/knowledge/light_rag.py +0 -273
  468. agno/knowledge/llamaindex.py +0 -66
  469. agno/knowledge/markdown.py +0 -154
  470. agno/knowledge/pdf.py +0 -164
  471. agno/knowledge/pdf_bytes.py +0 -42
  472. agno/knowledge/pdf_url.py +0 -148
  473. agno/knowledge/s3/__init__.py +0 -0
  474. agno/knowledge/s3/base.py +0 -64
  475. agno/knowledge/s3/pdf.py +0 -33
  476. agno/knowledge/s3/text.py +0 -34
  477. agno/knowledge/text.py +0 -141
  478. agno/knowledge/url.py +0 -46
  479. agno/knowledge/website.py +0 -179
  480. agno/knowledge/wikipedia.py +0 -32
  481. agno/knowledge/youtube.py +0 -35
  482. agno/memory/agent.py +0 -423
  483. agno/memory/classifier.py +0 -104
  484. agno/memory/db/__init__.py +0 -5
  485. agno/memory/db/base.py +0 -42
  486. agno/memory/db/mongodb.py +0 -189
  487. agno/memory/db/postgres.py +0 -203
  488. agno/memory/db/sqlite.py +0 -193
  489. agno/memory/memory.py +0 -22
  490. agno/memory/row.py +0 -36
  491. agno/memory/summarizer.py +0 -201
  492. agno/memory/summary.py +0 -19
  493. agno/memory/team.py +0 -415
  494. agno/memory/v2/__init__.py +0 -2
  495. agno/memory/v2/db/__init__.py +0 -1
  496. agno/memory/v2/db/base.py +0 -42
  497. agno/memory/v2/db/firestore.py +0 -339
  498. agno/memory/v2/db/mongodb.py +0 -196
  499. agno/memory/v2/db/postgres.py +0 -214
  500. agno/memory/v2/db/redis.py +0 -187
  501. agno/memory/v2/db/schema.py +0 -54
  502. agno/memory/v2/db/sqlite.py +0 -209
  503. agno/memory/v2/manager.py +0 -437
  504. agno/memory/v2/memory.py +0 -1097
  505. agno/memory/v2/schema.py +0 -55
  506. agno/memory/v2/summarizer.py +0 -215
  507. agno/memory/workflow.py +0 -38
  508. agno/models/ollama/tools.py +0 -430
  509. agno/models/qwen/__init__.py +0 -5
  510. agno/playground/__init__.py +0 -10
  511. agno/playground/deploy.py +0 -3
  512. agno/playground/playground.py +0 -3
  513. agno/playground/serve.py +0 -3
  514. agno/playground/settings.py +0 -3
  515. agno/reranker/__init__.py +0 -0
  516. agno/run/v2/__init__.py +0 -0
  517. agno/run/v2/workflow.py +0 -567
  518. agno/storage/__init__.py +0 -0
  519. agno/storage/agent/__init__.py +0 -0
  520. agno/storage/agent/dynamodb.py +0 -1
  521. agno/storage/agent/json.py +0 -1
  522. agno/storage/agent/mongodb.py +0 -1
  523. agno/storage/agent/postgres.py +0 -1
  524. agno/storage/agent/singlestore.py +0 -1
  525. agno/storage/agent/sqlite.py +0 -1
  526. agno/storage/agent/yaml.py +0 -1
  527. agno/storage/base.py +0 -60
  528. agno/storage/dynamodb.py +0 -673
  529. agno/storage/firestore.py +0 -297
  530. agno/storage/gcs_json.py +0 -261
  531. agno/storage/in_memory.py +0 -234
  532. agno/storage/json.py +0 -237
  533. agno/storage/mongodb.py +0 -328
  534. agno/storage/mysql.py +0 -685
  535. agno/storage/postgres.py +0 -682
  536. agno/storage/redis.py +0 -336
  537. agno/storage/session/__init__.py +0 -16
  538. agno/storage/session/agent.py +0 -64
  539. agno/storage/session/team.py +0 -63
  540. agno/storage/session/v2/__init__.py +0 -5
  541. agno/storage/session/workflow.py +0 -61
  542. agno/storage/singlestore.py +0 -606
  543. agno/storage/sqlite.py +0 -646
  544. agno/storage/workflow/__init__.py +0 -0
  545. agno/storage/workflow/mongodb.py +0 -1
  546. agno/storage/workflow/postgres.py +0 -1
  547. agno/storage/workflow/sqlite.py +0 -1
  548. agno/storage/yaml.py +0 -241
  549. agno/tools/thinking.py +0 -73
  550. agno/utils/defaults.py +0 -57
  551. agno/utils/filesystem.py +0 -39
  552. agno/utils/git.py +0 -52
  553. agno/utils/json_io.py +0 -30
  554. agno/utils/load_env.py +0 -19
  555. agno/utils/py_io.py +0 -19
  556. agno/utils/pyproject.py +0 -18
  557. agno/utils/resource_filter.py +0 -31
  558. agno/workflow/v2/__init__.py +0 -21
  559. agno/workflow/v2/types.py +0 -357
  560. agno/workflow/v2/workflow.py +0 -3312
  561. agno/workspace/__init__.py +0 -0
  562. agno/workspace/config.py +0 -325
  563. agno/workspace/enums.py +0 -6
  564. agno/workspace/helpers.py +0 -52
  565. agno/workspace/operator.py +0 -757
  566. agno/workspace/settings.py +0 -158
  567. agno-1.8.1.dist-info/METADATA +0 -982
  568. agno-1.8.1.dist-info/RECORD +0 -566
  569. agno-1.8.1.dist-info/entry_points.txt +0 -3
  570. /agno/{app → db/migrations}/__init__.py +0 -0
  571. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  572. /agno/{cli → integrations}/__init__.py +0 -0
  573. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  574. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  575. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  576. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  577. /agno/{app → os/interfaces}/slack/security.py +0 -0
  578. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  579. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  580. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  581. {agno-1.8.1.dist-info → agno-2.0.0rc1.dist-info}/WHEEL +0 -0
  582. {agno-1.8.1.dist-info → agno-2.0.0rc1.dist-info}/licenses/LICENSE +0 -0
  583. {agno-1.8.1.dist-info → agno-2.0.0rc1.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