agno 1.8.1__py3-none-any.whl → 2.0.0a1__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 (580) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +2778 -4123
  4. agno/api/agent.py +9 -65
  5. agno/api/api.py +5 -46
  6. agno/api/evals.py +6 -17
  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 +9 -64
  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 +1749 -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 +1438 -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 +888 -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 +1051 -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 +1417 -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 +298 -0
  52. agno/db/postgres/__init__.py +3 -0
  53. agno/db/postgres/postgres.py +1720 -0
  54. agno/db/postgres/schemas.py +124 -0
  55. agno/db/postgres/utils.py +281 -0
  56. agno/db/redis/__init__.py +3 -0
  57. agno/db/redis/redis.py +1371 -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 +1722 -0
  67. agno/db/singlestore/utils.py +327 -0
  68. agno/db/sqlite/__init__.py +3 -0
  69. agno/db/sqlite/schemas.py +119 -0
  70. agno/db/sqlite/sqlite.py +1680 -0
  71. agno/db/sqlite/utils.py +269 -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 +10 -10
  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 +129 -82
  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 +38 -144
  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 +393 -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 +65 -28
  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 +33 -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 +30 -0
  184. agno/os/router.py +843 -0
  185. agno/os/routers/__init__.py +3 -0
  186. agno/os/routers/evals/__init__.py +3 -0
  187. agno/os/routers/evals/evals.py +204 -0
  188. agno/os/routers/evals/schemas.py +142 -0
  189. agno/os/routers/evals/utils.py +161 -0
  190. agno/os/routers/knowledge/__init__.py +3 -0
  191. agno/os/routers/knowledge/knowledge.py +413 -0
  192. agno/os/routers/knowledge/schemas.py +118 -0
  193. agno/os/routers/memory/__init__.py +3 -0
  194. agno/os/routers/memory/memory.py +179 -0
  195. agno/os/routers/memory/schemas.py +58 -0
  196. agno/os/routers/metrics/__init__.py +3 -0
  197. agno/os/routers/metrics/metrics.py +58 -0
  198. agno/os/routers/metrics/schemas.py +47 -0
  199. agno/os/routers/session/__init__.py +3 -0
  200. agno/os/routers/session/session.py +163 -0
  201. agno/os/schema.py +892 -0
  202. agno/{app/playground → os}/settings.py +8 -15
  203. agno/os/utils.py +270 -0
  204. agno/reasoning/azure_ai_foundry.py +4 -4
  205. agno/reasoning/deepseek.py +4 -4
  206. agno/reasoning/default.py +6 -11
  207. agno/reasoning/groq.py +4 -4
  208. agno/reasoning/helpers.py +4 -6
  209. agno/reasoning/ollama.py +4 -4
  210. agno/reasoning/openai.py +4 -4
  211. agno/run/{response.py → agent.py} +144 -72
  212. agno/run/base.py +44 -58
  213. agno/run/cancel.py +83 -0
  214. agno/run/team.py +133 -77
  215. agno/run/workflow.py +537 -12
  216. agno/session/__init__.py +10 -0
  217. agno/session/agent.py +244 -0
  218. agno/session/summary.py +225 -0
  219. agno/session/team.py +262 -0
  220. agno/{storage/session/v2 → session}/workflow.py +47 -24
  221. agno/team/__init__.py +15 -16
  222. agno/team/team.py +2961 -4253
  223. agno/tools/agentql.py +14 -5
  224. agno/tools/airflow.py +9 -4
  225. agno/tools/api.py +7 -3
  226. agno/tools/apify.py +2 -46
  227. agno/tools/arxiv.py +8 -3
  228. agno/tools/aws_lambda.py +7 -5
  229. agno/tools/aws_ses.py +7 -1
  230. agno/tools/baidusearch.py +4 -1
  231. agno/tools/bitbucket.py +4 -4
  232. agno/tools/brandfetch.py +14 -11
  233. agno/tools/bravesearch.py +4 -1
  234. agno/tools/brightdata.py +42 -22
  235. agno/tools/browserbase.py +13 -4
  236. agno/tools/calcom.py +12 -10
  237. agno/tools/calculator.py +10 -27
  238. agno/tools/cartesia.py +18 -13
  239. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  240. agno/tools/confluence.py +8 -8
  241. agno/tools/crawl4ai.py +7 -1
  242. agno/tools/csv_toolkit.py +9 -8
  243. agno/tools/dalle.py +18 -11
  244. agno/tools/daytona.py +13 -16
  245. agno/tools/decorator.py +6 -3
  246. agno/tools/desi_vocal.py +16 -7
  247. agno/tools/discord.py +11 -8
  248. agno/tools/docker.py +30 -42
  249. agno/tools/duckdb.py +34 -53
  250. agno/tools/duckduckgo.py +8 -7
  251. agno/tools/e2b.py +61 -61
  252. agno/tools/eleven_labs.py +35 -28
  253. agno/tools/email.py +4 -1
  254. agno/tools/evm.py +7 -1
  255. agno/tools/exa.py +19 -14
  256. agno/tools/fal.py +29 -29
  257. agno/tools/file.py +9 -8
  258. agno/tools/financial_datasets.py +25 -44
  259. agno/tools/firecrawl.py +22 -22
  260. agno/tools/function.py +68 -17
  261. agno/tools/giphy.py +22 -10
  262. agno/tools/github.py +48 -126
  263. agno/tools/gmail.py +45 -61
  264. agno/tools/google_bigquery.py +7 -6
  265. agno/tools/google_maps.py +11 -26
  266. agno/tools/googlesearch.py +7 -2
  267. agno/tools/googlesheets.py +21 -17
  268. agno/tools/hackernews.py +9 -5
  269. agno/tools/jina.py +5 -4
  270. agno/tools/jira.py +18 -9
  271. agno/tools/knowledge.py +31 -32
  272. agno/tools/linear.py +18 -33
  273. agno/tools/linkup.py +5 -1
  274. agno/tools/local_file_system.py +8 -5
  275. agno/tools/lumalab.py +31 -19
  276. agno/tools/mem0.py +18 -12
  277. agno/tools/memori.py +14 -10
  278. agno/tools/mlx_transcribe.py +3 -2
  279. agno/tools/models/azure_openai.py +32 -14
  280. agno/tools/models/gemini.py +58 -31
  281. agno/tools/models/groq.py +29 -20
  282. agno/tools/models/nebius.py +27 -11
  283. agno/tools/models_labs.py +39 -15
  284. agno/tools/moviepy_video.py +7 -6
  285. agno/tools/neo4j.py +10 -8
  286. agno/tools/newspaper.py +7 -2
  287. agno/tools/newspaper4k.py +8 -3
  288. agno/tools/openai.py +57 -26
  289. agno/tools/openbb.py +12 -11
  290. agno/tools/opencv.py +62 -46
  291. agno/tools/openweather.py +14 -12
  292. agno/tools/pandas.py +11 -3
  293. agno/tools/postgres.py +4 -12
  294. agno/tools/pubmed.py +4 -1
  295. agno/tools/python.py +9 -22
  296. agno/tools/reasoning.py +35 -27
  297. agno/tools/reddit.py +11 -26
  298. agno/tools/replicate.py +54 -41
  299. agno/tools/resend.py +4 -1
  300. agno/tools/scrapegraph.py +15 -14
  301. agno/tools/searxng.py +10 -23
  302. agno/tools/serpapi.py +6 -3
  303. agno/tools/serper.py +13 -4
  304. agno/tools/shell.py +9 -2
  305. agno/tools/slack.py +12 -11
  306. agno/tools/sleep.py +3 -2
  307. agno/tools/spider.py +24 -4
  308. agno/tools/sql.py +7 -6
  309. agno/tools/tavily.py +6 -4
  310. agno/tools/telegram.py +12 -4
  311. agno/tools/todoist.py +11 -31
  312. agno/tools/toolkit.py +1 -1
  313. agno/tools/trafilatura.py +22 -6
  314. agno/tools/trello.py +9 -22
  315. agno/tools/twilio.py +10 -3
  316. agno/tools/user_control_flow.py +6 -1
  317. agno/tools/valyu.py +34 -5
  318. agno/tools/visualization.py +19 -28
  319. agno/tools/webbrowser.py +4 -3
  320. agno/tools/webex.py +11 -7
  321. agno/tools/website.py +15 -46
  322. agno/tools/webtools.py +12 -4
  323. agno/tools/whatsapp.py +5 -9
  324. agno/tools/wikipedia.py +20 -13
  325. agno/tools/x.py +14 -13
  326. agno/tools/yfinance.py +13 -40
  327. agno/tools/youtube.py +26 -20
  328. agno/tools/zendesk.py +7 -2
  329. agno/tools/zep.py +10 -7
  330. agno/tools/zoom.py +10 -9
  331. agno/utils/common.py +1 -19
  332. agno/utils/events.py +95 -118
  333. agno/utils/knowledge.py +29 -0
  334. agno/utils/log.py +2 -2
  335. agno/utils/mcp.py +11 -5
  336. agno/utils/media.py +39 -0
  337. agno/utils/message.py +12 -1
  338. agno/utils/models/claude.py +6 -4
  339. agno/utils/models/mistral.py +8 -7
  340. agno/utils/models/schema_utils.py +3 -3
  341. agno/utils/pprint.py +33 -32
  342. agno/utils/print_response/agent.py +779 -0
  343. agno/utils/print_response/team.py +1565 -0
  344. agno/utils/print_response/workflow.py +1451 -0
  345. agno/utils/prompts.py +14 -14
  346. agno/utils/reasoning.py +87 -0
  347. agno/utils/response.py +42 -42
  348. agno/utils/string.py +8 -22
  349. agno/utils/team.py +50 -0
  350. agno/utils/timer.py +2 -2
  351. agno/vectordb/base.py +33 -21
  352. agno/vectordb/cassandra/cassandra.py +287 -23
  353. agno/vectordb/chroma/chromadb.py +482 -59
  354. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  355. agno/vectordb/couchbase/couchbase.py +309 -29
  356. agno/vectordb/lancedb/lance_db.py +360 -21
  357. agno/vectordb/langchaindb/__init__.py +5 -0
  358. agno/vectordb/langchaindb/langchaindb.py +145 -0
  359. agno/vectordb/lightrag/__init__.py +5 -0
  360. agno/vectordb/lightrag/lightrag.py +374 -0
  361. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  362. agno/vectordb/milvus/milvus.py +242 -32
  363. agno/vectordb/mongodb/mongodb.py +200 -24
  364. agno/vectordb/pgvector/pgvector.py +319 -37
  365. agno/vectordb/pineconedb/pineconedb.py +221 -27
  366. agno/vectordb/qdrant/qdrant.py +334 -14
  367. agno/vectordb/singlestore/singlestore.py +286 -29
  368. agno/vectordb/surrealdb/surrealdb.py +187 -7
  369. agno/vectordb/upstashdb/upstashdb.py +342 -26
  370. agno/vectordb/weaviate/weaviate.py +227 -165
  371. agno/workflow/__init__.py +17 -13
  372. agno/workflow/{v2/condition.py → condition.py} +135 -32
  373. agno/workflow/{v2/loop.py → loop.py} +115 -28
  374. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  375. agno/workflow/{v2/router.py → router.py} +133 -32
  376. agno/workflow/{v2/step.py → step.py} +200 -42
  377. agno/workflow/{v2/steps.py → steps.py} +147 -66
  378. agno/workflow/types.py +482 -0
  379. agno/workflow/workflow.py +2394 -696
  380. agno-2.0.0a1.dist-info/METADATA +355 -0
  381. agno-2.0.0a1.dist-info/RECORD +514 -0
  382. agno/agent/metrics.py +0 -107
  383. agno/api/app.py +0 -35
  384. agno/api/playground.py +0 -92
  385. agno/api/schemas/app.py +0 -12
  386. agno/api/schemas/playground.py +0 -22
  387. agno/api/schemas/user.py +0 -35
  388. agno/api/schemas/workspace.py +0 -46
  389. agno/api/user.py +0 -160
  390. agno/api/workflows.py +0 -33
  391. agno/api/workspace.py +0 -175
  392. agno/app/agui/__init__.py +0 -3
  393. agno/app/agui/app.py +0 -17
  394. agno/app/agui/sync_router.py +0 -120
  395. agno/app/base.py +0 -186
  396. agno/app/discord/__init__.py +0 -3
  397. agno/app/fastapi/__init__.py +0 -3
  398. agno/app/fastapi/app.py +0 -107
  399. agno/app/fastapi/async_router.py +0 -457
  400. agno/app/fastapi/sync_router.py +0 -448
  401. agno/app/playground/app.py +0 -228
  402. agno/app/playground/async_router.py +0 -1050
  403. agno/app/playground/deploy.py +0 -249
  404. agno/app/playground/operator.py +0 -183
  405. agno/app/playground/schemas.py +0 -220
  406. agno/app/playground/serve.py +0 -55
  407. agno/app/playground/sync_router.py +0 -1042
  408. agno/app/playground/utils.py +0 -46
  409. agno/app/settings.py +0 -15
  410. agno/app/slack/__init__.py +0 -3
  411. agno/app/slack/app.py +0 -19
  412. agno/app/slack/sync_router.py +0 -92
  413. agno/app/utils.py +0 -54
  414. agno/app/whatsapp/__init__.py +0 -3
  415. agno/app/whatsapp/app.py +0 -15
  416. agno/app/whatsapp/sync_router.py +0 -197
  417. agno/cli/auth_server.py +0 -249
  418. agno/cli/config.py +0 -274
  419. agno/cli/console.py +0 -88
  420. agno/cli/credentials.py +0 -23
  421. agno/cli/entrypoint.py +0 -571
  422. agno/cli/operator.py +0 -357
  423. agno/cli/settings.py +0 -96
  424. agno/cli/ws/ws_cli.py +0 -817
  425. agno/constants.py +0 -13
  426. agno/document/__init__.py +0 -5
  427. agno/document/chunking/semantic.py +0 -45
  428. agno/document/chunking/strategy.py +0 -31
  429. agno/document/reader/__init__.py +0 -5
  430. agno/document/reader/base.py +0 -47
  431. agno/document/reader/docx_reader.py +0 -60
  432. agno/document/reader/gcs/pdf_reader.py +0 -44
  433. agno/document/reader/s3/pdf_reader.py +0 -59
  434. agno/document/reader/s3/text_reader.py +0 -63
  435. agno/document/reader/url_reader.py +0 -59
  436. agno/document/reader/youtube_reader.py +0 -58
  437. agno/embedder/__init__.py +0 -5
  438. agno/embedder/langdb.py +0 -80
  439. agno/embedder/mistral.py +0 -82
  440. agno/embedder/openai.py +0 -78
  441. agno/file/__init__.py +0 -5
  442. agno/file/file.py +0 -16
  443. agno/file/local/csv.py +0 -32
  444. agno/file/local/txt.py +0 -19
  445. agno/infra/app.py +0 -240
  446. agno/infra/base.py +0 -144
  447. agno/infra/context.py +0 -20
  448. agno/infra/db_app.py +0 -52
  449. agno/infra/resource.py +0 -205
  450. agno/infra/resources.py +0 -55
  451. agno/knowledge/agent.py +0 -702
  452. agno/knowledge/arxiv.py +0 -33
  453. agno/knowledge/combined.py +0 -36
  454. agno/knowledge/csv.py +0 -144
  455. agno/knowledge/csv_url.py +0 -124
  456. agno/knowledge/document.py +0 -223
  457. agno/knowledge/docx.py +0 -137
  458. agno/knowledge/firecrawl.py +0 -34
  459. agno/knowledge/gcs/__init__.py +0 -0
  460. agno/knowledge/gcs/base.py +0 -39
  461. agno/knowledge/gcs/pdf.py +0 -125
  462. agno/knowledge/json.py +0 -137
  463. agno/knowledge/langchain.py +0 -71
  464. agno/knowledge/light_rag.py +0 -273
  465. agno/knowledge/llamaindex.py +0 -66
  466. agno/knowledge/markdown.py +0 -154
  467. agno/knowledge/pdf.py +0 -164
  468. agno/knowledge/pdf_bytes.py +0 -42
  469. agno/knowledge/pdf_url.py +0 -148
  470. agno/knowledge/s3/__init__.py +0 -0
  471. agno/knowledge/s3/base.py +0 -64
  472. agno/knowledge/s3/pdf.py +0 -33
  473. agno/knowledge/s3/text.py +0 -34
  474. agno/knowledge/text.py +0 -141
  475. agno/knowledge/url.py +0 -46
  476. agno/knowledge/website.py +0 -179
  477. agno/knowledge/wikipedia.py +0 -32
  478. agno/knowledge/youtube.py +0 -35
  479. agno/memory/agent.py +0 -423
  480. agno/memory/classifier.py +0 -104
  481. agno/memory/db/__init__.py +0 -5
  482. agno/memory/db/base.py +0 -42
  483. agno/memory/db/mongodb.py +0 -189
  484. agno/memory/db/postgres.py +0 -203
  485. agno/memory/db/sqlite.py +0 -193
  486. agno/memory/memory.py +0 -22
  487. agno/memory/row.py +0 -36
  488. agno/memory/summarizer.py +0 -201
  489. agno/memory/summary.py +0 -19
  490. agno/memory/team.py +0 -415
  491. agno/memory/v2/__init__.py +0 -2
  492. agno/memory/v2/db/__init__.py +0 -1
  493. agno/memory/v2/db/base.py +0 -42
  494. agno/memory/v2/db/firestore.py +0 -339
  495. agno/memory/v2/db/mongodb.py +0 -196
  496. agno/memory/v2/db/postgres.py +0 -214
  497. agno/memory/v2/db/redis.py +0 -187
  498. agno/memory/v2/db/schema.py +0 -54
  499. agno/memory/v2/db/sqlite.py +0 -209
  500. agno/memory/v2/manager.py +0 -437
  501. agno/memory/v2/memory.py +0 -1097
  502. agno/memory/v2/schema.py +0 -55
  503. agno/memory/v2/summarizer.py +0 -215
  504. agno/memory/workflow.py +0 -38
  505. agno/models/ollama/tools.py +0 -430
  506. agno/models/qwen/__init__.py +0 -5
  507. agno/playground/__init__.py +0 -10
  508. agno/playground/deploy.py +0 -3
  509. agno/playground/playground.py +0 -3
  510. agno/playground/serve.py +0 -3
  511. agno/playground/settings.py +0 -3
  512. agno/reranker/__init__.py +0 -0
  513. agno/run/v2/__init__.py +0 -0
  514. agno/run/v2/workflow.py +0 -567
  515. agno/storage/__init__.py +0 -0
  516. agno/storage/agent/__init__.py +0 -0
  517. agno/storage/agent/dynamodb.py +0 -1
  518. agno/storage/agent/json.py +0 -1
  519. agno/storage/agent/mongodb.py +0 -1
  520. agno/storage/agent/postgres.py +0 -1
  521. agno/storage/agent/singlestore.py +0 -1
  522. agno/storage/agent/sqlite.py +0 -1
  523. agno/storage/agent/yaml.py +0 -1
  524. agno/storage/base.py +0 -60
  525. agno/storage/dynamodb.py +0 -673
  526. agno/storage/firestore.py +0 -297
  527. agno/storage/gcs_json.py +0 -261
  528. agno/storage/in_memory.py +0 -234
  529. agno/storage/json.py +0 -237
  530. agno/storage/mongodb.py +0 -328
  531. agno/storage/mysql.py +0 -685
  532. agno/storage/postgres.py +0 -682
  533. agno/storage/redis.py +0 -336
  534. agno/storage/session/__init__.py +0 -16
  535. agno/storage/session/agent.py +0 -64
  536. agno/storage/session/team.py +0 -63
  537. agno/storage/session/v2/__init__.py +0 -5
  538. agno/storage/session/workflow.py +0 -61
  539. agno/storage/singlestore.py +0 -606
  540. agno/storage/sqlite.py +0 -646
  541. agno/storage/workflow/__init__.py +0 -0
  542. agno/storage/workflow/mongodb.py +0 -1
  543. agno/storage/workflow/postgres.py +0 -1
  544. agno/storage/workflow/sqlite.py +0 -1
  545. agno/storage/yaml.py +0 -241
  546. agno/tools/thinking.py +0 -73
  547. agno/utils/defaults.py +0 -57
  548. agno/utils/filesystem.py +0 -39
  549. agno/utils/git.py +0 -52
  550. agno/utils/json_io.py +0 -30
  551. agno/utils/load_env.py +0 -19
  552. agno/utils/py_io.py +0 -19
  553. agno/utils/pyproject.py +0 -18
  554. agno/utils/resource_filter.py +0 -31
  555. agno/workflow/v2/__init__.py +0 -21
  556. agno/workflow/v2/types.py +0 -357
  557. agno/workflow/v2/workflow.py +0 -3312
  558. agno/workspace/__init__.py +0 -0
  559. agno/workspace/config.py +0 -325
  560. agno/workspace/enums.py +0 -6
  561. agno/workspace/helpers.py +0 -52
  562. agno/workspace/operator.py +0 -757
  563. agno/workspace/settings.py +0 -158
  564. agno-1.8.1.dist-info/METADATA +0 -982
  565. agno-1.8.1.dist-info/RECORD +0 -566
  566. agno-1.8.1.dist-info/entry_points.txt +0 -3
  567. /agno/{app → db/migrations}/__init__.py +0 -0
  568. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  569. /agno/{cli → integrations}/__init__.py +0 -0
  570. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  571. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  572. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  573. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  574. /agno/{app → os/interfaces}/slack/security.py +0 -0
  575. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  576. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  577. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  578. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/WHEEL +0 -0
  579. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
  580. {agno-1.8.1.dist-info → agno-2.0.0a1.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