agno 1.8.0__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 (583) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +2781 -4126
  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/media.py +2 -2
  137. agno/memory/__init__.py +2 -10
  138. agno/memory/manager.py +1003 -148
  139. agno/models/aimlapi/__init__.py +2 -2
  140. agno/models/aimlapi/aimlapi.py +6 -6
  141. agno/models/anthropic/claude.py +129 -82
  142. agno/models/aws/bedrock.py +107 -175
  143. agno/models/aws/claude.py +64 -18
  144. agno/models/azure/ai_foundry.py +73 -23
  145. agno/models/base.py +347 -287
  146. agno/models/cerebras/cerebras.py +84 -27
  147. agno/models/cohere/chat.py +106 -98
  148. agno/models/dashscope/dashscope.py +14 -5
  149. agno/models/google/gemini.py +123 -53
  150. agno/models/groq/groq.py +97 -35
  151. agno/models/huggingface/huggingface.py +92 -27
  152. agno/models/ibm/watsonx.py +72 -13
  153. agno/models/litellm/chat.py +85 -13
  154. agno/models/message.py +38 -144
  155. agno/models/meta/llama.py +85 -49
  156. agno/models/metrics.py +120 -0
  157. agno/models/mistral/mistral.py +90 -21
  158. agno/models/ollama/__init__.py +0 -2
  159. agno/models/ollama/chat.py +84 -46
  160. agno/models/openai/chat.py +135 -27
  161. agno/models/openai/responses.py +233 -115
  162. agno/models/perplexity/perplexity.py +26 -2
  163. agno/models/portkey/portkey.py +0 -7
  164. agno/models/response.py +14 -8
  165. agno/models/utils.py +20 -0
  166. agno/models/vercel/__init__.py +2 -2
  167. agno/models/vercel/v0.py +1 -1
  168. agno/models/vllm/__init__.py +2 -2
  169. agno/models/vllm/vllm.py +3 -3
  170. agno/models/xai/xai.py +10 -10
  171. agno/os/__init__.py +3 -0
  172. agno/os/app.py +393 -0
  173. agno/os/auth.py +47 -0
  174. agno/os/config.py +103 -0
  175. agno/os/interfaces/agui/__init__.py +3 -0
  176. agno/os/interfaces/agui/agui.py +31 -0
  177. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  178. agno/{app → os/interfaces}/agui/utils.py +65 -28
  179. agno/os/interfaces/base.py +21 -0
  180. agno/os/interfaces/slack/__init__.py +3 -0
  181. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  182. agno/os/interfaces/slack/slack.py +33 -0
  183. agno/os/interfaces/whatsapp/__init__.py +3 -0
  184. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  185. agno/os/interfaces/whatsapp/whatsapp.py +30 -0
  186. agno/os/router.py +843 -0
  187. agno/os/routers/__init__.py +3 -0
  188. agno/os/routers/evals/__init__.py +3 -0
  189. agno/os/routers/evals/evals.py +204 -0
  190. agno/os/routers/evals/schemas.py +142 -0
  191. agno/os/routers/evals/utils.py +161 -0
  192. agno/os/routers/knowledge/__init__.py +3 -0
  193. agno/os/routers/knowledge/knowledge.py +413 -0
  194. agno/os/routers/knowledge/schemas.py +118 -0
  195. agno/os/routers/memory/__init__.py +3 -0
  196. agno/os/routers/memory/memory.py +179 -0
  197. agno/os/routers/memory/schemas.py +58 -0
  198. agno/os/routers/metrics/__init__.py +3 -0
  199. agno/os/routers/metrics/metrics.py +58 -0
  200. agno/os/routers/metrics/schemas.py +47 -0
  201. agno/os/routers/session/__init__.py +3 -0
  202. agno/os/routers/session/session.py +163 -0
  203. agno/os/schema.py +892 -0
  204. agno/{app/playground → os}/settings.py +8 -15
  205. agno/os/utils.py +270 -0
  206. agno/reasoning/azure_ai_foundry.py +4 -4
  207. agno/reasoning/deepseek.py +4 -4
  208. agno/reasoning/default.py +6 -11
  209. agno/reasoning/groq.py +4 -4
  210. agno/reasoning/helpers.py +4 -6
  211. agno/reasoning/ollama.py +4 -4
  212. agno/reasoning/openai.py +4 -4
  213. agno/run/{response.py → agent.py} +144 -72
  214. agno/run/base.py +44 -58
  215. agno/run/cancel.py +83 -0
  216. agno/run/team.py +133 -77
  217. agno/run/workflow.py +537 -12
  218. agno/session/__init__.py +10 -0
  219. agno/session/agent.py +244 -0
  220. agno/session/summary.py +225 -0
  221. agno/session/team.py +262 -0
  222. agno/{storage/session/v2 → session}/workflow.py +47 -24
  223. agno/team/__init__.py +15 -16
  224. agno/team/team.py +2967 -4243
  225. agno/tools/agentql.py +14 -5
  226. agno/tools/airflow.py +9 -4
  227. agno/tools/api.py +7 -3
  228. agno/tools/apify.py +2 -46
  229. agno/tools/arxiv.py +8 -3
  230. agno/tools/aws_lambda.py +7 -5
  231. agno/tools/aws_ses.py +7 -1
  232. agno/tools/baidusearch.py +4 -1
  233. agno/tools/bitbucket.py +4 -4
  234. agno/tools/brandfetch.py +14 -11
  235. agno/tools/bravesearch.py +4 -1
  236. agno/tools/brightdata.py +42 -22
  237. agno/tools/browserbase.py +13 -4
  238. agno/tools/calcom.py +12 -10
  239. agno/tools/calculator.py +10 -27
  240. agno/tools/cartesia.py +18 -13
  241. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  242. agno/tools/confluence.py +71 -18
  243. agno/tools/crawl4ai.py +7 -1
  244. agno/tools/csv_toolkit.py +9 -8
  245. agno/tools/dalle.py +18 -11
  246. agno/tools/daytona.py +13 -16
  247. agno/tools/decorator.py +6 -3
  248. agno/tools/desi_vocal.py +16 -7
  249. agno/tools/discord.py +11 -8
  250. agno/tools/docker.py +30 -42
  251. agno/tools/duckdb.py +34 -53
  252. agno/tools/duckduckgo.py +8 -7
  253. agno/tools/e2b.py +62 -62
  254. agno/tools/eleven_labs.py +35 -28
  255. agno/tools/email.py +4 -1
  256. agno/tools/evm.py +7 -1
  257. agno/tools/exa.py +19 -14
  258. agno/tools/fal.py +29 -29
  259. agno/tools/file.py +9 -8
  260. agno/tools/financial_datasets.py +25 -44
  261. agno/tools/firecrawl.py +22 -22
  262. agno/tools/function.py +68 -17
  263. agno/tools/giphy.py +22 -10
  264. agno/tools/github.py +48 -126
  265. agno/tools/gmail.py +46 -62
  266. agno/tools/google_bigquery.py +7 -6
  267. agno/tools/google_maps.py +11 -26
  268. agno/tools/googlesearch.py +7 -2
  269. agno/tools/googlesheets.py +21 -17
  270. agno/tools/hackernews.py +9 -5
  271. agno/tools/jina.py +5 -4
  272. agno/tools/jira.py +18 -9
  273. agno/tools/knowledge.py +31 -32
  274. agno/tools/linear.py +18 -33
  275. agno/tools/linkup.py +5 -1
  276. agno/tools/local_file_system.py +8 -5
  277. agno/tools/lumalab.py +31 -19
  278. agno/tools/mem0.py +18 -12
  279. agno/tools/memori.py +14 -10
  280. agno/tools/mlx_transcribe.py +3 -2
  281. agno/tools/models/azure_openai.py +32 -14
  282. agno/tools/models/gemini.py +58 -31
  283. agno/tools/models/groq.py +29 -20
  284. agno/tools/models/nebius.py +27 -11
  285. agno/tools/models_labs.py +39 -15
  286. agno/tools/moviepy_video.py +7 -6
  287. agno/tools/neo4j.py +134 -0
  288. agno/tools/newspaper.py +7 -2
  289. agno/tools/newspaper4k.py +8 -3
  290. agno/tools/openai.py +57 -26
  291. agno/tools/openbb.py +12 -11
  292. agno/tools/opencv.py +62 -46
  293. agno/tools/openweather.py +14 -12
  294. agno/tools/pandas.py +11 -3
  295. agno/tools/postgres.py +4 -12
  296. agno/tools/pubmed.py +4 -1
  297. agno/tools/python.py +9 -22
  298. agno/tools/reasoning.py +35 -27
  299. agno/tools/reddit.py +11 -26
  300. agno/tools/replicate.py +54 -41
  301. agno/tools/resend.py +4 -1
  302. agno/tools/scrapegraph.py +15 -14
  303. agno/tools/searxng.py +10 -23
  304. agno/tools/serpapi.py +6 -3
  305. agno/tools/serper.py +13 -4
  306. agno/tools/shell.py +9 -2
  307. agno/tools/slack.py +12 -11
  308. agno/tools/sleep.py +3 -2
  309. agno/tools/spider.py +24 -4
  310. agno/tools/sql.py +7 -6
  311. agno/tools/tavily.py +6 -4
  312. agno/tools/telegram.py +12 -4
  313. agno/tools/todoist.py +11 -31
  314. agno/tools/toolkit.py +1 -1
  315. agno/tools/trafilatura.py +22 -6
  316. agno/tools/trello.py +9 -22
  317. agno/tools/twilio.py +10 -3
  318. agno/tools/user_control_flow.py +6 -1
  319. agno/tools/valyu.py +34 -5
  320. agno/tools/visualization.py +19 -28
  321. agno/tools/webbrowser.py +4 -3
  322. agno/tools/webex.py +11 -7
  323. agno/tools/website.py +15 -46
  324. agno/tools/webtools.py +12 -4
  325. agno/tools/whatsapp.py +5 -9
  326. agno/tools/wikipedia.py +20 -13
  327. agno/tools/x.py +14 -13
  328. agno/tools/yfinance.py +13 -40
  329. agno/tools/youtube.py +26 -20
  330. agno/tools/zendesk.py +7 -2
  331. agno/tools/zep.py +10 -7
  332. agno/tools/zoom.py +10 -9
  333. agno/utils/common.py +1 -19
  334. agno/utils/events.py +95 -118
  335. agno/utils/knowledge.py +29 -0
  336. agno/utils/location.py +2 -2
  337. agno/utils/log.py +2 -2
  338. agno/utils/mcp.py +11 -5
  339. agno/utils/media.py +39 -0
  340. agno/utils/message.py +12 -1
  341. agno/utils/models/claude.py +6 -4
  342. agno/utils/models/mistral.py +8 -7
  343. agno/utils/models/schema_utils.py +3 -3
  344. agno/utils/pprint.py +33 -32
  345. agno/utils/print_response/agent.py +779 -0
  346. agno/utils/print_response/team.py +1565 -0
  347. agno/utils/print_response/workflow.py +1451 -0
  348. agno/utils/prompts.py +14 -14
  349. agno/utils/reasoning.py +87 -0
  350. agno/utils/response.py +42 -42
  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 +356 -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 +2394 -696
  383. agno-2.0.0a1.dist-info/METADATA +355 -0
  384. agno-2.0.0a1.dist-info/RECORD +514 -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 -698
  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.0.dist-info/METADATA +0 -979
  568. agno-1.8.0.dist-info/RECORD +0 -565
  569. agno-1.8.0.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.0.dist-info → agno-2.0.0a1.dist-info}/WHEEL +0 -0
  582. {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
  583. {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,10 @@
1
1
  import json
2
2
  import time
3
+ from collections.abc import AsyncIterator
3
4
  from dataclasses import dataclass
4
5
  from os import getenv
5
6
  from pathlib import Path
6
- from typing import Any, Dict, List, Optional, Type, Union
7
+ from typing import Any, Dict, Iterator, List, Optional, Type, Union
7
8
  from uuid import uuid4
8
9
 
9
10
  from pydantic import BaseModel
@@ -11,8 +12,10 @@ from pydantic import BaseModel
11
12
  from agno.exceptions import ModelProviderError
12
13
  from agno.media import Audio, File, ImageArtifact, Video
13
14
  from agno.models.base import Model
14
- from agno.models.message import Citations, Message, MessageMetrics, UrlCitation
15
+ from agno.models.message import Citations, Message, UrlCitation
16
+ from agno.models.metrics import Metrics
15
17
  from agno.models.response import ModelResponse
18
+ from agno.run.agent import RunOutput
16
19
  from agno.utils.gemini import convert_schema, format_function_definitions, format_image_for_message
17
20
  from agno.utils.log import log_debug, log_error, log_info, log_warning
18
21
  from agno.utils.models.schema_utils import get_response_schema_for_provider
@@ -262,21 +265,33 @@ class Gemini(Model):
262
265
  def invoke(
263
266
  self,
264
267
  messages: List[Message],
268
+ assistant_message: Message,
265
269
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
266
270
  tools: Optional[List[Dict[str, Any]]] = None,
267
271
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
268
- ):
272
+ run_response: Optional[RunOutput] = None,
273
+ ) -> ModelResponse:
269
274
  """
270
275
  Invokes the model with a list of messages and returns the response.
271
276
  """
272
277
  formatted_messages, system_message = self._format_messages(messages)
273
278
  request_kwargs = self.get_request_params(system_message, response_format=response_format, tools=tools)
274
279
  try:
275
- return self.get_client().models.generate_content(
280
+ if run_response and run_response.metrics:
281
+ run_response.metrics.set_time_to_first_token()
282
+
283
+ assistant_message.metrics.start_timer()
284
+ provider_response = self.get_client().models.generate_content(
276
285
  model=self.id,
277
286
  contents=formatted_messages,
278
287
  **request_kwargs,
279
288
  )
289
+ assistant_message.metrics.stop_timer()
290
+
291
+ model_response = self._parse_provider_response(provider_response, response_format=response_format)
292
+
293
+ return model_response
294
+
280
295
  except (ClientError, ServerError) as e:
281
296
  log_error(f"Error from Gemini API: {e}")
282
297
  error_message = str(e.response) if hasattr(e, "response") else str(e)
@@ -293,10 +308,12 @@ class Gemini(Model):
293
308
  def invoke_stream(
294
309
  self,
295
310
  messages: List[Message],
311
+ assistant_message: Message,
296
312
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
297
313
  tools: Optional[List[Dict[str, Any]]] = None,
298
314
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
299
- ):
315
+ run_response: Optional[RunOutput] = None,
316
+ ) -> Iterator[ModelResponse]:
300
317
  """
301
318
  Invokes the model with a list of messages and returns the response as a stream.
302
319
  """
@@ -304,11 +321,19 @@ class Gemini(Model):
304
321
 
305
322
  request_kwargs = self.get_request_params(system_message, response_format=response_format, tools=tools)
306
323
  try:
307
- yield from self.get_client().models.generate_content_stream(
324
+ if run_response and run_response.metrics:
325
+ run_response.metrics.set_time_to_first_token()
326
+
327
+ assistant_message.metrics.start_timer()
328
+ for response in self.get_client().models.generate_content_stream(
308
329
  model=self.id,
309
330
  contents=formatted_messages,
310
331
  **request_kwargs,
311
- )
332
+ ):
333
+ yield self._parse_provider_response_delta(response)
334
+
335
+ assistant_message.metrics.stop_timer()
336
+
312
337
  except (ClientError, ServerError) as e:
313
338
  log_error(f"Error from Gemini API: {e}")
314
339
  raise ModelProviderError(
@@ -324,10 +349,12 @@ class Gemini(Model):
324
349
  async def ainvoke(
325
350
  self,
326
351
  messages: List[Message],
352
+ assistant_message: Message,
327
353
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
328
354
  tools: Optional[List[Dict[str, Any]]] = None,
329
355
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
330
- ):
356
+ run_response: Optional[RunOutput] = None,
357
+ ) -> ModelResponse:
331
358
  """
332
359
  Invokes the model with a list of messages and returns the response.
333
360
  """
@@ -336,11 +363,21 @@ class Gemini(Model):
336
363
  request_kwargs = self.get_request_params(system_message, response_format=response_format, tools=tools)
337
364
 
338
365
  try:
339
- return await self.get_client().aio.models.generate_content(
366
+ if run_response and run_response.metrics:
367
+ run_response.metrics.set_time_to_first_token()
368
+
369
+ assistant_message.metrics.start_timer()
370
+ provider_response = await self.get_client().aio.models.generate_content(
340
371
  model=self.id,
341
372
  contents=formatted_messages,
342
373
  **request_kwargs,
343
374
  )
375
+ assistant_message.metrics.stop_timer()
376
+
377
+ model_response = self._parse_provider_response(provider_response, response_format=response_format)
378
+
379
+ return model_response
380
+
344
381
  except (ClientError, ServerError) as e:
345
382
  log_error(f"Error from Gemini API: {e}")
346
383
  raise ModelProviderError(
@@ -356,10 +393,12 @@ class Gemini(Model):
356
393
  async def ainvoke_stream(
357
394
  self,
358
395
  messages: List[Message],
396
+ assistant_message: Message,
359
397
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
360
398
  tools: Optional[List[Dict[str, Any]]] = None,
361
399
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
362
- ):
400
+ run_response: Optional[RunOutput] = None,
401
+ ) -> AsyncIterator[ModelResponse]:
363
402
  """
364
403
  Invokes the model with a list of messages and returns the response as a stream.
365
404
  """
@@ -368,13 +407,21 @@ class Gemini(Model):
368
407
  request_kwargs = self.get_request_params(system_message, response_format=response_format, tools=tools)
369
408
 
370
409
  try:
410
+ if run_response and run_response.metrics:
411
+ run_response.metrics.set_time_to_first_token()
412
+
413
+ assistant_message.metrics.start_timer()
414
+
371
415
  async_stream = await self.get_client().aio.models.generate_content_stream(
372
416
  model=self.id,
373
417
  contents=formatted_messages,
374
418
  **request_kwargs,
375
419
  )
376
420
  async for chunk in async_stream:
377
- yield chunk
421
+ yield self._parse_provider_response_delta(chunk)
422
+
423
+ assistant_message.metrics.stop_timer()
424
+
378
425
  except (ClientError, ServerError) as e:
379
426
  log_error(f"Error from Gemini API: {e}")
380
427
  raise ModelProviderError(
@@ -696,7 +743,7 @@ class Gemini(Model):
696
743
  """
697
744
  combined_content: List = []
698
745
  combined_function_result: List = []
699
- message_metrics = MessageMetrics()
746
+ message_metrics = Metrics()
700
747
  if len(function_call_results) > 0:
701
748
  for result in function_call_results:
702
749
  combined_content.append(result.content)
@@ -710,7 +757,7 @@ class Gemini(Model):
710
757
  )
711
758
  )
712
759
 
713
- def parse_provider_response(self, response: GenerateContentResponse, **kwargs) -> ModelResponse:
760
+ def _parse_provider_response(self, response: GenerateContentResponse, **kwargs) -> ModelResponse:
714
761
  """
715
762
  Parse the OpenAI response into a ModelResponse.
716
763
 
@@ -765,8 +812,12 @@ class Gemini(Model):
765
812
  model_response.content += content_str
766
813
 
767
814
  if hasattr(part, "inline_data") and part.inline_data is not None:
768
- model_response.image = ImageArtifact(
769
- id=str(uuid4()), content=part.inline_data.data, mime_type=part.inline_data.mime_type
815
+ if model_response.images is None:
816
+ model_response.images = []
817
+ model_response.images.append(
818
+ ImageArtifact(
819
+ id=str(uuid4()), content=part.inline_data.data, mime_type=part.inline_data.mime_type
820
+ )
770
821
  )
771
822
 
772
823
  # Extract function call if present
@@ -793,12 +844,18 @@ class Gemini(Model):
793
844
  grounding_metadata = response.candidates[0].grounding_metadata.model_dump()
794
845
  citations_raw["grounding_metadata"] = grounding_metadata
795
846
 
796
- chunks = grounding_metadata.get("grounding_chunks", [])
797
- citation_pairs = [
798
- (chunk.get("web", {}).get("uri"), chunk.get("web", {}).get("title"))
799
- for chunk in chunks
800
- if chunk.get("web", {}).get("uri")
801
- ]
847
+ chunks = grounding_metadata.get("grounding_chunks", []) or []
848
+ citation_pairs = []
849
+ for chunk in chunks:
850
+ if not isinstance(chunk, dict):
851
+ continue
852
+ web = chunk.get("web")
853
+ if not isinstance(web, dict):
854
+ continue
855
+ uri = web.get("uri")
856
+ title = web.get("title")
857
+ if uri:
858
+ citation_pairs.append((uri, title))
802
859
 
803
860
  # Create citation objects from filtered pairs
804
861
  grounding_urls = [UrlCitation(url=url, title=title) for url, title in citation_pairs]
@@ -830,18 +887,7 @@ class Gemini(Model):
830
887
 
831
888
  # Extract usage metadata if present
832
889
  if hasattr(response, "usage_metadata") and response.usage_metadata is not None:
833
- usage: GenerateContentResponseUsageMetadata = response.usage_metadata
834
-
835
- output_tokens = usage.candidates_token_count or 0
836
- if hasattr(usage, "thoughts_token_count") and usage.thoughts_token_count is not None:
837
- output_tokens += usage.thoughts_token_count or 0
838
-
839
- model_response.response_usage = {
840
- "input_tokens": usage.prompt_token_count or 0,
841
- "output_tokens": output_tokens,
842
- "total_tokens": usage.total_token_count or 0,
843
- "cached_tokens": usage.cached_content_token_count or 0,
844
- }
890
+ model_response.response_usage = self._get_metrics(response.usage_metadata)
845
891
 
846
892
  # If we have no content but have a role, add a default empty content
847
893
  if model_response.role and model_response.content is None and not model_response.tool_calls:
@@ -849,7 +895,7 @@ class Gemini(Model):
849
895
 
850
896
  return model_response
851
897
 
852
- def parse_provider_response_delta(self, response_delta: GenerateContentResponse) -> ModelResponse:
898
+ def _parse_provider_response_delta(self, response_delta: GenerateContentResponse) -> ModelResponse:
853
899
  model_response = ModelResponse()
854
900
 
855
901
  if response_delta.candidates and len(response_delta.candidates) > 0:
@@ -880,8 +926,12 @@ class Gemini(Model):
880
926
  model_response.content += text_content
881
927
 
882
928
  if hasattr(part, "inline_data") and part.inline_data is not None:
883
- model_response.image = ImageArtifact(
884
- id=str(uuid4()), content=part.inline_data.data, mime_type=part.inline_data.mime_type
929
+ if model_response.images is None:
930
+ model_response.images = []
931
+ model_response.images.append(
932
+ ImageArtifact(
933
+ id=str(uuid4()), content=part.inline_data.data, mime_type=part.inline_data.mime_type
934
+ )
885
935
  )
886
936
 
887
937
  # Extract function call if present
@@ -907,11 +957,17 @@ class Gemini(Model):
907
957
 
908
958
  # Extract url and title
909
959
  chunks = grounding_metadata.pop("grounding_chunks", None) or []
910
- citation_pairs = [
911
- (chunk.get("web", {}).get("uri"), chunk.get("web", {}).get("title"))
912
- for chunk in chunks
913
- if chunk.get("web", {}).get("uri")
914
- ]
960
+ citation_pairs = []
961
+ for chunk in chunks:
962
+ if not isinstance(chunk, dict):
963
+ continue
964
+ web = chunk.get("web")
965
+ if not isinstance(web, dict):
966
+ continue
967
+ uri = web.get("uri")
968
+ title = web.get("title")
969
+ if uri:
970
+ citation_pairs.append((uri, title))
915
971
 
916
972
  # Create citation objects from filtered pairs
917
973
  citations.urls = [UrlCitation(url=url, title=title) for url, title in citation_pairs]
@@ -920,18 +976,7 @@ class Gemini(Model):
920
976
 
921
977
  # Extract usage metadata if present
922
978
  if hasattr(response_delta, "usage_metadata") and response_delta.usage_metadata is not None:
923
- usage: GenerateContentResponseUsageMetadata = response_delta.usage_metadata
924
-
925
- output_tokens = usage.candidates_token_count or 0
926
- if hasattr(usage, "thoughts_token_count") and usage.thoughts_token_count is not None:
927
- output_tokens += usage.thoughts_token_count or 0
928
-
929
- model_response.response_usage = {
930
- "input_tokens": usage.prompt_token_count or 0,
931
- "output_tokens": output_tokens,
932
- "total_tokens": usage.total_token_count or 0,
933
- "cached_tokens": usage.cached_content_token_count or 0,
934
- }
979
+ model_response.response_usage = self._get_metrics(response_delta.usage_metadata)
935
980
 
936
981
  return model_response
937
982
 
@@ -972,3 +1017,28 @@ class Gemini(Model):
972
1017
  setattr(new_instance, "client", None)
973
1018
 
974
1019
  return new_instance
1020
+
1021
+ def _get_metrics(self, response_usage: GenerateContentResponseUsageMetadata) -> Metrics:
1022
+ """
1023
+ Parse the given Google Gemini usage into an Agno Metrics object.
1024
+
1025
+ Args:
1026
+ response_usage: Usage data from Google Gemini
1027
+
1028
+ Returns:
1029
+ Metrics: Parsed metrics data
1030
+ """
1031
+ metrics = Metrics()
1032
+
1033
+ metrics.input_tokens = response_usage.prompt_token_count or 0
1034
+ metrics.output_tokens = response_usage.candidates_token_count or 0
1035
+ metrics.total_tokens = metrics.input_tokens + metrics.output_tokens
1036
+ if response_usage.thoughts_token_count is not None:
1037
+ metrics.output_tokens += response_usage.thoughts_token_count or 0
1038
+
1039
+ metrics.cache_read_tokens = response_usage.cached_content_token_count or 0
1040
+
1041
+ if response_usage.traffic_type is not None:
1042
+ metrics.provider_metrics = {"traffic_type": response_usage.traffic_type}
1043
+
1044
+ return metrics
agno/models/groq/groq.py CHANGED
@@ -1,3 +1,4 @@
1
+ from collections.abc import AsyncIterator
1
2
  from dataclasses import dataclass
2
3
  from os import getenv
3
4
  from typing import Any, Dict, Iterator, List, Optional, Type, Union
@@ -8,7 +9,9 @@ from pydantic import BaseModel
8
9
  from agno.exceptions import ModelProviderError
9
10
  from agno.models.base import Model
10
11
  from agno.models.message import Message
12
+ from agno.models.metrics import Metrics
11
13
  from agno.models.response import ModelResponse
14
+ from agno.run.agent import RunOutput
12
15
  from agno.utils.log import log_debug, log_error, log_warning
13
16
  from agno.utils.openai import images_to_message
14
17
 
@@ -18,6 +21,7 @@ try:
18
21
  from groq import Groq as GroqClient
19
22
  from groq.types.chat import ChatCompletion
20
23
  from groq.types.chat.chat_completion_chunk import ChatCompletionChunk, ChoiceDelta, ChoiceDeltaToolCall
24
+ from groq.types.completion_usage import CompletionUsage
21
25
  except ImportError:
22
26
  raise ImportError("`groq` not installed. Please install using `pip install groq`")
23
27
 
@@ -250,19 +254,31 @@ class Groq(Model):
250
254
  def invoke(
251
255
  self,
252
256
  messages: List[Message],
257
+ assistant_message: Message,
253
258
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
254
259
  tools: Optional[List[Dict[str, Any]]] = None,
255
260
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
256
- ) -> ChatCompletion:
261
+ run_response: Optional[RunOutput] = None,
262
+ ) -> ModelResponse:
257
263
  """
258
264
  Send a chat completion request to the Groq API.
259
265
  """
260
266
  try:
261
- return self.get_client().chat.completions.create(
267
+ if run_response and run_response.metrics:
268
+ run_response.metrics.set_time_to_first_token()
269
+
270
+ assistant_message.metrics.start_timer()
271
+ provider_response = self.get_client().chat.completions.create(
262
272
  model=self.id,
263
273
  messages=[self.format_message(m) for m in messages], # type: ignore
264
274
  **self.get_request_params(response_format=response_format, tools=tools, tool_choice=tool_choice),
265
275
  )
276
+ assistant_message.metrics.stop_timer()
277
+
278
+ model_response = self._parse_provider_response(provider_response, response_format=response_format)
279
+
280
+ return model_response
281
+
266
282
  except (APIResponseValidationError, APIStatusError) as e:
267
283
  log_error(f"Error calling Groq API: {str(e)}")
268
284
  raise ModelProviderError(
@@ -278,19 +294,31 @@ class Groq(Model):
278
294
  async def ainvoke(
279
295
  self,
280
296
  messages: List[Message],
297
+ assistant_message: Message,
281
298
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
282
299
  tools: Optional[List[Dict[str, Any]]] = None,
283
300
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
284
- ) -> ChatCompletion:
301
+ run_response: Optional[RunOutput] = None,
302
+ ) -> ModelResponse:
285
303
  """
286
304
  Sends an asynchronous chat completion request to the Groq API.
287
305
  """
288
306
  try:
289
- return await self.get_async_client().chat.completions.create(
307
+ if run_response and run_response.metrics:
308
+ run_response.metrics.set_time_to_first_token()
309
+
310
+ assistant_message.metrics.start_timer()
311
+ response = await self.get_async_client().chat.completions.create(
290
312
  model=self.id,
291
313
  messages=[self.format_message(m) for m in messages], # type: ignore
292
314
  **self.get_request_params(response_format=response_format, tools=tools, tool_choice=tool_choice),
293
315
  )
316
+ assistant_message.metrics.stop_timer()
317
+
318
+ model_response = self._parse_provider_response(response, response_format=response_format)
319
+
320
+ return model_response
321
+
294
322
  except (APIResponseValidationError, APIStatusError) as e:
295
323
  log_error(f"Error calling Groq API: {str(e)}")
296
324
  raise ModelProviderError(
@@ -306,20 +334,31 @@ class Groq(Model):
306
334
  def invoke_stream(
307
335
  self,
308
336
  messages: List[Message],
337
+ assistant_message: Message,
309
338
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
310
339
  tools: Optional[List[Dict[str, Any]]] = None,
311
340
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
312
- ) -> Iterator[ChatCompletionChunk]:
341
+ run_response: Optional[RunOutput] = None,
342
+ ) -> Iterator[ModelResponse]:
313
343
  """
314
344
  Send a streaming chat completion request to the Groq API.
315
345
  """
316
346
  try:
317
- return self.get_client().chat.completions.create(
347
+ if run_response and run_response.metrics:
348
+ run_response.metrics.set_time_to_first_token()
349
+
350
+ assistant_message.metrics.start_timer()
351
+
352
+ for chunk in self.get_client().chat.completions.create(
318
353
  model=self.id,
319
354
  messages=[self.format_message(m) for m in messages], # type: ignore
320
355
  stream=True,
321
356
  **self.get_request_params(response_format=response_format, tools=tools, tool_choice=tool_choice),
322
- )
357
+ ):
358
+ yield self._parse_provider_response_delta(chunk) # type: ignore
359
+
360
+ assistant_message.metrics.stop_timer()
361
+
323
362
  except (APIResponseValidationError, APIStatusError) as e:
324
363
  log_error(f"Error calling Groq API: {str(e)}")
325
364
  raise ModelProviderError(
@@ -335,23 +374,33 @@ class Groq(Model):
335
374
  async def ainvoke_stream(
336
375
  self,
337
376
  messages: List[Message],
377
+ assistant_message: Message,
338
378
  response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
339
379
  tools: Optional[List[Dict[str, Any]]] = None,
340
380
  tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
341
- ) -> Any:
381
+ run_response: Optional[RunOutput] = None,
382
+ ) -> AsyncIterator[ModelResponse]:
342
383
  """
343
384
  Sends an asynchronous streaming chat completion request to the Groq API.
344
385
  """
345
386
 
346
387
  try:
347
- stream = await self.get_async_client().chat.completions.create(
388
+ if run_response and run_response.metrics:
389
+ run_response.metrics.set_time_to_first_token()
390
+
391
+ assistant_message.metrics.start_timer()
392
+
393
+ async_stream = await self.get_async_client().chat.completions.create(
348
394
  model=self.id,
349
395
  messages=[self.format_message(m) for m in messages], # type: ignore
350
396
  stream=True,
351
397
  **self.get_request_params(response_format=response_format, tools=tools, tool_choice=tool_choice),
352
398
  )
353
- async for chunk in stream: # type: ignore
354
- yield chunk
399
+ async for chunk in async_stream: # type: ignore
400
+ yield self._parse_provider_response_delta(chunk) # type: ignore
401
+
402
+ assistant_message.metrics.stop_timer()
403
+
355
404
  except (APIResponseValidationError, APIStatusError) as e:
356
405
  log_error(f"Error calling Groq API: {str(e)}")
357
406
  raise ModelProviderError(
@@ -405,7 +454,7 @@ class Groq(Model):
405
454
  tool_call_entry["type"] = _tool_call_type
406
455
  return tool_calls
407
456
 
408
- def parse_provider_response(self, response: ChatCompletion, **kwargs) -> ModelResponse:
457
+ def _parse_provider_response(self, response: ChatCompletion, **kwargs) -> ModelResponse:
409
458
  """
410
459
  Parse the Groq response into a ModelResponse.
411
460
 
@@ -437,20 +486,11 @@ class Groq(Model):
437
486
 
438
487
  # Add usage metrics if present
439
488
  if response.usage is not None:
440
- model_response.response_usage = {
441
- "input_tokens": response.usage.prompt_tokens,
442
- "output_tokens": response.usage.completion_tokens,
443
- "total_tokens": response.usage.total_tokens,
444
- "additional_metrics": {
445
- "completion_time": response.usage.completion_time,
446
- "prompt_time": response.usage.prompt_time,
447
- "queue_time": response.usage.queue_time,
448
- "total_time": response.usage.total_time,
449
- },
450
- }
489
+ model_response.response_usage = self._get_metrics(response.usage)
490
+
451
491
  return model_response
452
492
 
453
- def parse_provider_response_delta(self, response: ChatCompletionChunk) -> ModelResponse:
493
+ def _parse_provider_response_delta(self, response: ChatCompletionChunk) -> ModelResponse:
454
494
  """
455
495
  Parse the Groq streaming response into ModelResponse objects.
456
496
 
@@ -476,16 +516,38 @@ class Groq(Model):
476
516
 
477
517
  # Add usage metrics if present
478
518
  if response.x_groq is not None and response.x_groq.usage is not None:
479
- model_response.response_usage = {
480
- "input_tokens": response.x_groq.usage.prompt_tokens,
481
- "output_tokens": response.x_groq.usage.completion_tokens,
482
- "total_tokens": response.x_groq.usage.total_tokens,
483
- "additional_metrics": {
484
- "completion_time": response.x_groq.usage.completion_time,
485
- "prompt_time": response.x_groq.usage.prompt_time,
486
- "queue_time": response.x_groq.usage.queue_time,
487
- "total_time": response.x_groq.usage.total_time,
488
- },
489
- }
519
+ model_response.response_usage = self._get_metrics(response.x_groq.usage)
490
520
 
491
521
  return model_response
522
+
523
+ def _get_metrics(self, response_usage: CompletionUsage) -> Metrics:
524
+ """
525
+ Parse the given Groq usage into an Agno Metrics object.
526
+
527
+ Args:
528
+ response_usage: Usage data from Groq
529
+
530
+ Returns:
531
+ Metrics: Parsed metrics data
532
+ """
533
+ metrics = Metrics()
534
+
535
+ metrics.input_tokens = response_usage.prompt_tokens or 0
536
+ metrics.output_tokens = response_usage.completion_tokens or 0
537
+ metrics.total_tokens = metrics.input_tokens + metrics.output_tokens
538
+
539
+ # Additional time metrics offered by Groq
540
+ if completion_time := response_usage.completion_time:
541
+ metrics.provider_metrics = metrics.provider_metrics or {}
542
+ metrics.provider_metrics["completion_time"] = completion_time
543
+ if prompt_time := response_usage.prompt_time:
544
+ metrics.provider_metrics = metrics.provider_metrics or {}
545
+ metrics.provider_metrics["prompt_time"] = prompt_time
546
+ if queue_time := response_usage.queue_time:
547
+ metrics.provider_metrics = metrics.provider_metrics or {}
548
+ metrics.provider_metrics["queue_time"] = queue_time
549
+ if total_time := response_usage.total_time:
550
+ metrics.provider_metrics = metrics.provider_metrics or {}
551
+ metrics.provider_metrics["total_time"] = total_time
552
+
553
+ return metrics