agno 0.1.2__py3-none-any.whl → 2.3.13__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 (723) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +44 -5
  3. agno/agent/agent.py +10531 -2975
  4. agno/api/agent.py +14 -53
  5. agno/api/api.py +7 -46
  6. agno/api/evals.py +22 -0
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -25
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +6 -9
  11. agno/api/schemas/evals.py +16 -0
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +10 -10
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +16 -0
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +22 -26
  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/compression/__init__.py +3 -0
  25. agno/compression/manager.py +247 -0
  26. agno/culture/__init__.py +3 -0
  27. agno/culture/manager.py +956 -0
  28. agno/db/__init__.py +24 -0
  29. agno/db/async_postgres/__init__.py +3 -0
  30. agno/db/base.py +946 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2781 -0
  33. agno/db/dynamo/schemas.py +442 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +2379 -0
  37. agno/db/firestore/schemas.py +181 -0
  38. agno/db/firestore/utils.py +376 -0
  39. agno/db/gcs_json/__init__.py +3 -0
  40. agno/db/gcs_json/gcs_json_db.py +1791 -0
  41. agno/db/gcs_json/utils.py +228 -0
  42. agno/db/in_memory/__init__.py +3 -0
  43. agno/db/in_memory/in_memory_db.py +1312 -0
  44. agno/db/in_memory/utils.py +230 -0
  45. agno/db/json/__init__.py +3 -0
  46. agno/db/json/json_db.py +1777 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/manager.py +199 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/migrations/versions/v2_3_0.py +938 -0
  51. agno/db/mongo/__init__.py +17 -0
  52. agno/db/mongo/async_mongo.py +2760 -0
  53. agno/db/mongo/mongo.py +2597 -0
  54. agno/db/mongo/schemas.py +119 -0
  55. agno/db/mongo/utils.py +276 -0
  56. agno/db/mysql/__init__.py +4 -0
  57. agno/db/mysql/async_mysql.py +2912 -0
  58. agno/db/mysql/mysql.py +2923 -0
  59. agno/db/mysql/schemas.py +186 -0
  60. agno/db/mysql/utils.py +488 -0
  61. agno/db/postgres/__init__.py +4 -0
  62. agno/db/postgres/async_postgres.py +2579 -0
  63. agno/db/postgres/postgres.py +2870 -0
  64. agno/db/postgres/schemas.py +187 -0
  65. agno/db/postgres/utils.py +442 -0
  66. agno/db/redis/__init__.py +3 -0
  67. agno/db/redis/redis.py +2141 -0
  68. agno/db/redis/schemas.py +159 -0
  69. agno/db/redis/utils.py +346 -0
  70. agno/db/schemas/__init__.py +4 -0
  71. agno/db/schemas/culture.py +120 -0
  72. agno/db/schemas/evals.py +34 -0
  73. agno/db/schemas/knowledge.py +40 -0
  74. agno/db/schemas/memory.py +61 -0
  75. agno/db/singlestore/__init__.py +3 -0
  76. agno/db/singlestore/schemas.py +179 -0
  77. agno/db/singlestore/singlestore.py +2877 -0
  78. agno/db/singlestore/utils.py +384 -0
  79. agno/db/sqlite/__init__.py +4 -0
  80. agno/db/sqlite/async_sqlite.py +2911 -0
  81. agno/db/sqlite/schemas.py +181 -0
  82. agno/db/sqlite/sqlite.py +2908 -0
  83. agno/db/sqlite/utils.py +429 -0
  84. agno/db/surrealdb/__init__.py +3 -0
  85. agno/db/surrealdb/metrics.py +292 -0
  86. agno/db/surrealdb/models.py +334 -0
  87. agno/db/surrealdb/queries.py +71 -0
  88. agno/db/surrealdb/surrealdb.py +1908 -0
  89. agno/db/surrealdb/utils.py +147 -0
  90. agno/db/utils.py +118 -0
  91. agno/eval/__init__.py +24 -0
  92. agno/eval/accuracy.py +666 -276
  93. agno/eval/agent_as_judge.py +861 -0
  94. agno/eval/base.py +29 -0
  95. agno/eval/performance.py +779 -0
  96. agno/eval/reliability.py +241 -62
  97. agno/eval/utils.py +120 -0
  98. agno/exceptions.py +143 -1
  99. agno/filters.py +354 -0
  100. agno/guardrails/__init__.py +6 -0
  101. agno/guardrails/base.py +19 -0
  102. agno/guardrails/openai.py +144 -0
  103. agno/guardrails/pii.py +94 -0
  104. agno/guardrails/prompt_injection.py +52 -0
  105. agno/hooks/__init__.py +3 -0
  106. agno/hooks/decorator.py +164 -0
  107. agno/integrations/discord/__init__.py +3 -0
  108. agno/integrations/discord/client.py +203 -0
  109. agno/knowledge/__init__.py +5 -1
  110. agno/{document → knowledge}/chunking/agentic.py +22 -14
  111. agno/{document → knowledge}/chunking/document.py +2 -2
  112. agno/{document → knowledge}/chunking/fixed.py +7 -6
  113. agno/knowledge/chunking/markdown.py +151 -0
  114. agno/{document → knowledge}/chunking/recursive.py +15 -3
  115. agno/knowledge/chunking/row.py +39 -0
  116. agno/knowledge/chunking/semantic.py +91 -0
  117. agno/knowledge/chunking/strategy.py +165 -0
  118. agno/knowledge/content.py +74 -0
  119. agno/knowledge/document/__init__.py +5 -0
  120. agno/{document → knowledge/document}/base.py +12 -2
  121. agno/knowledge/embedder/__init__.py +5 -0
  122. agno/knowledge/embedder/aws_bedrock.py +343 -0
  123. agno/knowledge/embedder/azure_openai.py +210 -0
  124. agno/{embedder → knowledge/embedder}/base.py +8 -0
  125. agno/knowledge/embedder/cohere.py +323 -0
  126. agno/knowledge/embedder/fastembed.py +62 -0
  127. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  128. agno/knowledge/embedder/google.py +258 -0
  129. agno/knowledge/embedder/huggingface.py +94 -0
  130. agno/knowledge/embedder/jina.py +182 -0
  131. agno/knowledge/embedder/langdb.py +22 -0
  132. agno/knowledge/embedder/mistral.py +206 -0
  133. agno/knowledge/embedder/nebius.py +13 -0
  134. agno/knowledge/embedder/ollama.py +154 -0
  135. agno/knowledge/embedder/openai.py +195 -0
  136. agno/knowledge/embedder/sentence_transformer.py +63 -0
  137. agno/{embedder → knowledge/embedder}/together.py +1 -1
  138. agno/knowledge/embedder/vllm.py +262 -0
  139. agno/knowledge/embedder/voyageai.py +165 -0
  140. agno/knowledge/knowledge.py +3006 -0
  141. agno/knowledge/reader/__init__.py +7 -0
  142. agno/knowledge/reader/arxiv_reader.py +81 -0
  143. agno/knowledge/reader/base.py +95 -0
  144. agno/knowledge/reader/csv_reader.py +164 -0
  145. agno/knowledge/reader/docx_reader.py +82 -0
  146. agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
  147. agno/knowledge/reader/firecrawl_reader.py +201 -0
  148. agno/knowledge/reader/json_reader.py +88 -0
  149. agno/knowledge/reader/markdown_reader.py +137 -0
  150. agno/knowledge/reader/pdf_reader.py +431 -0
  151. agno/knowledge/reader/pptx_reader.py +101 -0
  152. agno/knowledge/reader/reader_factory.py +313 -0
  153. agno/knowledge/reader/s3_reader.py +89 -0
  154. agno/knowledge/reader/tavily_reader.py +193 -0
  155. agno/knowledge/reader/text_reader.py +127 -0
  156. agno/knowledge/reader/web_search_reader.py +325 -0
  157. agno/knowledge/reader/website_reader.py +455 -0
  158. agno/knowledge/reader/wikipedia_reader.py +91 -0
  159. agno/knowledge/reader/youtube_reader.py +78 -0
  160. agno/knowledge/remote_content/remote_content.py +88 -0
  161. agno/knowledge/reranker/__init__.py +3 -0
  162. agno/{reranker → knowledge/reranker}/base.py +1 -1
  163. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  164. agno/knowledge/reranker/infinity.py +195 -0
  165. agno/knowledge/reranker/sentence_transformer.py +54 -0
  166. agno/knowledge/types.py +39 -0
  167. agno/knowledge/utils.py +234 -0
  168. agno/media.py +439 -95
  169. agno/memory/__init__.py +16 -3
  170. agno/memory/manager.py +1474 -123
  171. agno/memory/strategies/__init__.py +15 -0
  172. agno/memory/strategies/base.py +66 -0
  173. agno/memory/strategies/summarize.py +196 -0
  174. agno/memory/strategies/types.py +37 -0
  175. agno/models/aimlapi/__init__.py +5 -0
  176. agno/models/aimlapi/aimlapi.py +62 -0
  177. agno/models/anthropic/__init__.py +4 -0
  178. agno/models/anthropic/claude.py +960 -496
  179. agno/models/aws/__init__.py +15 -0
  180. agno/models/aws/bedrock.py +686 -451
  181. agno/models/aws/claude.py +190 -183
  182. agno/models/azure/__init__.py +18 -1
  183. agno/models/azure/ai_foundry.py +489 -0
  184. agno/models/azure/openai_chat.py +89 -40
  185. agno/models/base.py +2477 -550
  186. agno/models/cerebras/__init__.py +12 -0
  187. agno/models/cerebras/cerebras.py +565 -0
  188. agno/models/cerebras/cerebras_openai.py +131 -0
  189. agno/models/cohere/__init__.py +4 -0
  190. agno/models/cohere/chat.py +306 -492
  191. agno/models/cometapi/__init__.py +5 -0
  192. agno/models/cometapi/cometapi.py +74 -0
  193. agno/models/dashscope/__init__.py +5 -0
  194. agno/models/dashscope/dashscope.py +90 -0
  195. agno/models/deepinfra/__init__.py +5 -0
  196. agno/models/deepinfra/deepinfra.py +45 -0
  197. agno/models/deepseek/__init__.py +4 -0
  198. agno/models/deepseek/deepseek.py +110 -9
  199. agno/models/fireworks/__init__.py +4 -0
  200. agno/models/fireworks/fireworks.py +19 -22
  201. agno/models/google/__init__.py +3 -7
  202. agno/models/google/gemini.py +1717 -662
  203. agno/models/google/utils.py +22 -0
  204. agno/models/groq/__init__.py +4 -0
  205. agno/models/groq/groq.py +391 -666
  206. agno/models/huggingface/__init__.py +4 -0
  207. agno/models/huggingface/huggingface.py +266 -538
  208. agno/models/ibm/__init__.py +5 -0
  209. agno/models/ibm/watsonx.py +432 -0
  210. agno/models/internlm/__init__.py +3 -0
  211. agno/models/internlm/internlm.py +20 -3
  212. agno/models/langdb/__init__.py +1 -0
  213. agno/models/langdb/langdb.py +60 -0
  214. agno/models/litellm/__init__.py +14 -0
  215. agno/models/litellm/chat.py +503 -0
  216. agno/models/litellm/litellm_openai.py +42 -0
  217. agno/models/llama_cpp/__init__.py +5 -0
  218. agno/models/llama_cpp/llama_cpp.py +22 -0
  219. agno/models/lmstudio/__init__.py +5 -0
  220. agno/models/lmstudio/lmstudio.py +25 -0
  221. agno/models/message.py +361 -39
  222. agno/models/meta/__init__.py +12 -0
  223. agno/models/meta/llama.py +502 -0
  224. agno/models/meta/llama_openai.py +79 -0
  225. agno/models/metrics.py +120 -0
  226. agno/models/mistral/__init__.py +4 -0
  227. agno/models/mistral/mistral.py +293 -393
  228. agno/models/nebius/__init__.py +3 -0
  229. agno/models/nebius/nebius.py +53 -0
  230. agno/models/nexus/__init__.py +3 -0
  231. agno/models/nexus/nexus.py +22 -0
  232. agno/models/nvidia/__init__.py +4 -0
  233. agno/models/nvidia/nvidia.py +22 -3
  234. agno/models/ollama/__init__.py +4 -2
  235. agno/models/ollama/chat.py +257 -492
  236. agno/models/openai/__init__.py +7 -0
  237. agno/models/openai/chat.py +725 -770
  238. agno/models/openai/like.py +16 -2
  239. agno/models/openai/responses.py +1121 -0
  240. agno/models/openrouter/__init__.py +4 -0
  241. agno/models/openrouter/openrouter.py +62 -5
  242. agno/models/perplexity/__init__.py +5 -0
  243. agno/models/perplexity/perplexity.py +203 -0
  244. agno/models/portkey/__init__.py +3 -0
  245. agno/models/portkey/portkey.py +82 -0
  246. agno/models/requesty/__init__.py +5 -0
  247. agno/models/requesty/requesty.py +69 -0
  248. agno/models/response.py +177 -7
  249. agno/models/sambanova/__init__.py +4 -0
  250. agno/models/sambanova/sambanova.py +23 -4
  251. agno/models/siliconflow/__init__.py +5 -0
  252. agno/models/siliconflow/siliconflow.py +42 -0
  253. agno/models/together/__init__.py +4 -0
  254. agno/models/together/together.py +21 -164
  255. agno/models/utils.py +266 -0
  256. agno/models/vercel/__init__.py +3 -0
  257. agno/models/vercel/v0.py +43 -0
  258. agno/models/vertexai/__init__.py +0 -1
  259. agno/models/vertexai/claude.py +190 -0
  260. agno/models/vllm/__init__.py +3 -0
  261. agno/models/vllm/vllm.py +83 -0
  262. agno/models/xai/__init__.py +2 -0
  263. agno/models/xai/xai.py +111 -7
  264. agno/os/__init__.py +3 -0
  265. agno/os/app.py +1027 -0
  266. agno/os/auth.py +244 -0
  267. agno/os/config.py +126 -0
  268. agno/os/interfaces/__init__.py +1 -0
  269. agno/os/interfaces/a2a/__init__.py +3 -0
  270. agno/os/interfaces/a2a/a2a.py +42 -0
  271. agno/os/interfaces/a2a/router.py +249 -0
  272. agno/os/interfaces/a2a/utils.py +924 -0
  273. agno/os/interfaces/agui/__init__.py +3 -0
  274. agno/os/interfaces/agui/agui.py +47 -0
  275. agno/os/interfaces/agui/router.py +147 -0
  276. agno/os/interfaces/agui/utils.py +574 -0
  277. agno/os/interfaces/base.py +25 -0
  278. agno/os/interfaces/slack/__init__.py +3 -0
  279. agno/os/interfaces/slack/router.py +148 -0
  280. agno/os/interfaces/slack/security.py +30 -0
  281. agno/os/interfaces/slack/slack.py +47 -0
  282. agno/os/interfaces/whatsapp/__init__.py +3 -0
  283. agno/os/interfaces/whatsapp/router.py +210 -0
  284. agno/os/interfaces/whatsapp/security.py +55 -0
  285. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  286. agno/os/mcp.py +293 -0
  287. agno/os/middleware/__init__.py +9 -0
  288. agno/os/middleware/jwt.py +797 -0
  289. agno/os/router.py +258 -0
  290. agno/os/routers/__init__.py +3 -0
  291. agno/os/routers/agents/__init__.py +3 -0
  292. agno/os/routers/agents/router.py +599 -0
  293. agno/os/routers/agents/schema.py +261 -0
  294. agno/os/routers/evals/__init__.py +3 -0
  295. agno/os/routers/evals/evals.py +450 -0
  296. agno/os/routers/evals/schemas.py +174 -0
  297. agno/os/routers/evals/utils.py +231 -0
  298. agno/os/routers/health.py +31 -0
  299. agno/os/routers/home.py +52 -0
  300. agno/os/routers/knowledge/__init__.py +3 -0
  301. agno/os/routers/knowledge/knowledge.py +1008 -0
  302. agno/os/routers/knowledge/schemas.py +178 -0
  303. agno/os/routers/memory/__init__.py +3 -0
  304. agno/os/routers/memory/memory.py +661 -0
  305. agno/os/routers/memory/schemas.py +88 -0
  306. agno/os/routers/metrics/__init__.py +3 -0
  307. agno/os/routers/metrics/metrics.py +190 -0
  308. agno/os/routers/metrics/schemas.py +47 -0
  309. agno/os/routers/session/__init__.py +3 -0
  310. agno/os/routers/session/session.py +997 -0
  311. agno/os/routers/teams/__init__.py +3 -0
  312. agno/os/routers/teams/router.py +512 -0
  313. agno/os/routers/teams/schema.py +257 -0
  314. agno/os/routers/traces/__init__.py +3 -0
  315. agno/os/routers/traces/schemas.py +414 -0
  316. agno/os/routers/traces/traces.py +499 -0
  317. agno/os/routers/workflows/__init__.py +3 -0
  318. agno/os/routers/workflows/router.py +624 -0
  319. agno/os/routers/workflows/schema.py +75 -0
  320. agno/os/schema.py +534 -0
  321. agno/os/scopes.py +469 -0
  322. agno/{playground → os}/settings.py +7 -15
  323. agno/os/utils.py +973 -0
  324. agno/reasoning/anthropic.py +80 -0
  325. agno/reasoning/azure_ai_foundry.py +67 -0
  326. agno/reasoning/deepseek.py +63 -0
  327. agno/reasoning/default.py +97 -0
  328. agno/reasoning/gemini.py +73 -0
  329. agno/reasoning/groq.py +71 -0
  330. agno/reasoning/helpers.py +24 -1
  331. agno/reasoning/ollama.py +67 -0
  332. agno/reasoning/openai.py +86 -0
  333. agno/reasoning/step.py +2 -1
  334. agno/reasoning/vertexai.py +76 -0
  335. agno/run/__init__.py +6 -0
  336. agno/run/agent.py +822 -0
  337. agno/run/base.py +247 -0
  338. agno/run/cancel.py +81 -0
  339. agno/run/requirement.py +181 -0
  340. agno/run/team.py +767 -0
  341. agno/run/workflow.py +708 -0
  342. agno/session/__init__.py +10 -0
  343. agno/session/agent.py +260 -0
  344. agno/session/summary.py +265 -0
  345. agno/session/team.py +342 -0
  346. agno/session/workflow.py +501 -0
  347. agno/table.py +10 -0
  348. agno/team/__init__.py +37 -0
  349. agno/team/team.py +9536 -0
  350. agno/tools/__init__.py +7 -0
  351. agno/tools/agentql.py +120 -0
  352. agno/tools/airflow.py +22 -12
  353. agno/tools/api.py +122 -0
  354. agno/tools/apify.py +276 -83
  355. agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
  356. agno/tools/aws_lambda.py +28 -7
  357. agno/tools/aws_ses.py +66 -0
  358. agno/tools/baidusearch.py +11 -4
  359. agno/tools/bitbucket.py +292 -0
  360. agno/tools/brandfetch.py +213 -0
  361. agno/tools/bravesearch.py +106 -0
  362. agno/tools/brightdata.py +367 -0
  363. agno/tools/browserbase.py +209 -0
  364. agno/tools/calcom.py +32 -23
  365. agno/tools/calculator.py +24 -37
  366. agno/tools/cartesia.py +187 -0
  367. agno/tools/{clickup_tool.py → clickup.py} +17 -28
  368. agno/tools/confluence.py +91 -26
  369. agno/tools/crawl4ai.py +139 -43
  370. agno/tools/csv_toolkit.py +28 -22
  371. agno/tools/dalle.py +36 -22
  372. agno/tools/daytona.py +475 -0
  373. agno/tools/decorator.py +169 -14
  374. agno/tools/desi_vocal.py +23 -11
  375. agno/tools/discord.py +32 -29
  376. agno/tools/docker.py +716 -0
  377. agno/tools/duckdb.py +76 -81
  378. agno/tools/duckduckgo.py +43 -40
  379. agno/tools/e2b.py +703 -0
  380. agno/tools/eleven_labs.py +65 -54
  381. agno/tools/email.py +13 -5
  382. agno/tools/evm.py +129 -0
  383. agno/tools/exa.py +324 -42
  384. agno/tools/fal.py +39 -35
  385. agno/tools/file.py +196 -30
  386. agno/tools/file_generation.py +356 -0
  387. agno/tools/financial_datasets.py +288 -0
  388. agno/tools/firecrawl.py +108 -33
  389. agno/tools/function.py +960 -122
  390. agno/tools/giphy.py +34 -12
  391. agno/tools/github.py +1294 -97
  392. agno/tools/gmail.py +922 -0
  393. agno/tools/google_bigquery.py +117 -0
  394. agno/tools/google_drive.py +271 -0
  395. agno/tools/google_maps.py +253 -0
  396. agno/tools/googlecalendar.py +607 -107
  397. agno/tools/googlesheets.py +377 -0
  398. agno/tools/hackernews.py +20 -12
  399. agno/tools/jina.py +24 -14
  400. agno/tools/jira.py +48 -19
  401. agno/tools/knowledge.py +218 -0
  402. agno/tools/linear.py +82 -43
  403. agno/tools/linkup.py +58 -0
  404. agno/tools/local_file_system.py +15 -7
  405. agno/tools/lumalab.py +41 -26
  406. agno/tools/mcp/__init__.py +10 -0
  407. agno/tools/mcp/mcp.py +331 -0
  408. agno/tools/mcp/multi_mcp.py +347 -0
  409. agno/tools/mcp/params.py +24 -0
  410. agno/tools/mcp_toolbox.py +284 -0
  411. agno/tools/mem0.py +193 -0
  412. agno/tools/memory.py +419 -0
  413. agno/tools/mlx_transcribe.py +11 -9
  414. agno/tools/models/azure_openai.py +190 -0
  415. agno/tools/models/gemini.py +203 -0
  416. agno/tools/models/groq.py +158 -0
  417. agno/tools/models/morph.py +186 -0
  418. agno/tools/models/nebius.py +124 -0
  419. agno/tools/models_labs.py +163 -82
  420. agno/tools/moviepy_video.py +18 -13
  421. agno/tools/nano_banana.py +151 -0
  422. agno/tools/neo4j.py +134 -0
  423. agno/tools/newspaper.py +15 -4
  424. agno/tools/newspaper4k.py +19 -6
  425. agno/tools/notion.py +204 -0
  426. agno/tools/openai.py +181 -17
  427. agno/tools/openbb.py +27 -20
  428. agno/tools/opencv.py +321 -0
  429. agno/tools/openweather.py +233 -0
  430. agno/tools/oxylabs.py +385 -0
  431. agno/tools/pandas.py +25 -15
  432. agno/tools/parallel.py +314 -0
  433. agno/tools/postgres.py +238 -185
  434. agno/tools/pubmed.py +125 -13
  435. agno/tools/python.py +48 -35
  436. agno/tools/reasoning.py +283 -0
  437. agno/tools/reddit.py +207 -29
  438. agno/tools/redshift.py +406 -0
  439. agno/tools/replicate.py +69 -26
  440. agno/tools/resend.py +11 -6
  441. agno/tools/scrapegraph.py +179 -19
  442. agno/tools/searxng.py +23 -31
  443. agno/tools/serpapi.py +15 -10
  444. agno/tools/serper.py +255 -0
  445. agno/tools/shell.py +23 -12
  446. agno/tools/shopify.py +1519 -0
  447. agno/tools/slack.py +56 -14
  448. agno/tools/sleep.py +8 -6
  449. agno/tools/spider.py +35 -11
  450. agno/tools/spotify.py +919 -0
  451. agno/tools/sql.py +34 -19
  452. agno/tools/tavily.py +158 -8
  453. agno/tools/telegram.py +18 -8
  454. agno/tools/todoist.py +218 -0
  455. agno/tools/toolkit.py +134 -9
  456. agno/tools/trafilatura.py +388 -0
  457. agno/tools/trello.py +25 -28
  458. agno/tools/twilio.py +18 -9
  459. agno/tools/user_control_flow.py +78 -0
  460. agno/tools/valyu.py +228 -0
  461. agno/tools/visualization.py +467 -0
  462. agno/tools/webbrowser.py +28 -0
  463. agno/tools/webex.py +76 -0
  464. agno/tools/website.py +23 -19
  465. agno/tools/webtools.py +45 -0
  466. agno/tools/whatsapp.py +286 -0
  467. agno/tools/wikipedia.py +28 -19
  468. agno/tools/workflow.py +285 -0
  469. agno/tools/{twitter.py → x.py} +142 -46
  470. agno/tools/yfinance.py +41 -39
  471. agno/tools/youtube.py +34 -17
  472. agno/tools/zendesk.py +15 -5
  473. agno/tools/zep.py +454 -0
  474. agno/tools/zoom.py +86 -37
  475. agno/tracing/__init__.py +12 -0
  476. agno/tracing/exporter.py +157 -0
  477. agno/tracing/schemas.py +276 -0
  478. agno/tracing/setup.py +111 -0
  479. agno/utils/agent.py +938 -0
  480. agno/utils/audio.py +37 -1
  481. agno/utils/certs.py +27 -0
  482. agno/utils/code_execution.py +11 -0
  483. agno/utils/common.py +103 -20
  484. agno/utils/cryptography.py +22 -0
  485. agno/utils/dttm.py +33 -0
  486. agno/utils/events.py +700 -0
  487. agno/utils/functions.py +107 -37
  488. agno/utils/gemini.py +426 -0
  489. agno/utils/hooks.py +171 -0
  490. agno/utils/http.py +185 -0
  491. agno/utils/json_schema.py +159 -37
  492. agno/utils/knowledge.py +36 -0
  493. agno/utils/location.py +19 -0
  494. agno/utils/log.py +221 -8
  495. agno/utils/mcp.py +214 -0
  496. agno/utils/media.py +335 -14
  497. agno/utils/merge_dict.py +22 -1
  498. agno/utils/message.py +77 -2
  499. agno/utils/models/ai_foundry.py +50 -0
  500. agno/utils/models/claude.py +373 -0
  501. agno/utils/models/cohere.py +94 -0
  502. agno/utils/models/llama.py +85 -0
  503. agno/utils/models/mistral.py +100 -0
  504. agno/utils/models/openai_responses.py +140 -0
  505. agno/utils/models/schema_utils.py +153 -0
  506. agno/utils/models/watsonx.py +41 -0
  507. agno/utils/openai.py +257 -0
  508. agno/utils/pickle.py +1 -1
  509. agno/utils/pprint.py +124 -8
  510. agno/utils/print_response/agent.py +930 -0
  511. agno/utils/print_response/team.py +1914 -0
  512. agno/utils/print_response/workflow.py +1668 -0
  513. agno/utils/prompts.py +111 -0
  514. agno/utils/reasoning.py +108 -0
  515. agno/utils/response.py +163 -0
  516. agno/utils/serialize.py +32 -0
  517. agno/utils/shell.py +4 -4
  518. agno/utils/streamlit.py +487 -0
  519. agno/utils/string.py +204 -51
  520. agno/utils/team.py +139 -0
  521. agno/utils/timer.py +9 -2
  522. agno/utils/tokens.py +657 -0
  523. agno/utils/tools.py +19 -1
  524. agno/utils/whatsapp.py +305 -0
  525. agno/utils/yaml_io.py +3 -3
  526. agno/vectordb/__init__.py +2 -0
  527. agno/vectordb/base.py +87 -9
  528. agno/vectordb/cassandra/__init__.py +5 -1
  529. agno/vectordb/cassandra/cassandra.py +383 -27
  530. agno/vectordb/chroma/__init__.py +4 -0
  531. agno/vectordb/chroma/chromadb.py +748 -83
  532. agno/vectordb/clickhouse/__init__.py +7 -1
  533. agno/vectordb/clickhouse/clickhousedb.py +554 -53
  534. agno/vectordb/couchbase/__init__.py +3 -0
  535. agno/vectordb/couchbase/couchbase.py +1446 -0
  536. agno/vectordb/lancedb/__init__.py +5 -0
  537. agno/vectordb/lancedb/lance_db.py +730 -98
  538. agno/vectordb/langchaindb/__init__.py +5 -0
  539. agno/vectordb/langchaindb/langchaindb.py +163 -0
  540. agno/vectordb/lightrag/__init__.py +5 -0
  541. agno/vectordb/lightrag/lightrag.py +388 -0
  542. agno/vectordb/llamaindex/__init__.py +3 -0
  543. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  544. agno/vectordb/milvus/__init__.py +3 -0
  545. agno/vectordb/milvus/milvus.py +966 -78
  546. agno/vectordb/mongodb/__init__.py +9 -1
  547. agno/vectordb/mongodb/mongodb.py +1175 -172
  548. agno/vectordb/pgvector/__init__.py +8 -0
  549. agno/vectordb/pgvector/pgvector.py +599 -115
  550. agno/vectordb/pineconedb/__init__.py +5 -1
  551. agno/vectordb/pineconedb/pineconedb.py +406 -43
  552. agno/vectordb/qdrant/__init__.py +4 -0
  553. agno/vectordb/qdrant/qdrant.py +914 -61
  554. agno/vectordb/redis/__init__.py +9 -0
  555. agno/vectordb/redis/redisdb.py +682 -0
  556. agno/vectordb/singlestore/__init__.py +8 -1
  557. agno/vectordb/singlestore/singlestore.py +771 -0
  558. agno/vectordb/surrealdb/__init__.py +3 -0
  559. agno/vectordb/surrealdb/surrealdb.py +663 -0
  560. agno/vectordb/upstashdb/__init__.py +5 -0
  561. agno/vectordb/upstashdb/upstashdb.py +718 -0
  562. agno/vectordb/weaviate/__init__.py +8 -0
  563. agno/vectordb/weaviate/index.py +15 -0
  564. agno/vectordb/weaviate/weaviate.py +1009 -0
  565. agno/workflow/__init__.py +23 -1
  566. agno/workflow/agent.py +299 -0
  567. agno/workflow/condition.py +759 -0
  568. agno/workflow/loop.py +756 -0
  569. agno/workflow/parallel.py +853 -0
  570. agno/workflow/router.py +723 -0
  571. agno/workflow/step.py +1564 -0
  572. agno/workflow/steps.py +613 -0
  573. agno/workflow/types.py +556 -0
  574. agno/workflow/workflow.py +4327 -514
  575. agno-2.3.13.dist-info/METADATA +639 -0
  576. agno-2.3.13.dist-info/RECORD +613 -0
  577. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
  578. agno-2.3.13.dist-info/licenses/LICENSE +201 -0
  579. agno/api/playground.py +0 -91
  580. agno/api/schemas/playground.py +0 -22
  581. agno/api/schemas/user.py +0 -22
  582. agno/api/schemas/workspace.py +0 -46
  583. agno/api/user.py +0 -160
  584. agno/api/workspace.py +0 -151
  585. agno/cli/auth_server.py +0 -118
  586. agno/cli/config.py +0 -275
  587. agno/cli/console.py +0 -88
  588. agno/cli/credentials.py +0 -23
  589. agno/cli/entrypoint.py +0 -571
  590. agno/cli/operator.py +0 -355
  591. agno/cli/settings.py +0 -85
  592. agno/cli/ws/ws_cli.py +0 -817
  593. agno/constants.py +0 -13
  594. agno/document/__init__.py +0 -1
  595. agno/document/chunking/semantic.py +0 -47
  596. agno/document/chunking/strategy.py +0 -31
  597. agno/document/reader/__init__.py +0 -1
  598. agno/document/reader/arxiv_reader.py +0 -41
  599. agno/document/reader/base.py +0 -22
  600. agno/document/reader/csv_reader.py +0 -84
  601. agno/document/reader/docx_reader.py +0 -46
  602. agno/document/reader/firecrawl_reader.py +0 -99
  603. agno/document/reader/json_reader.py +0 -43
  604. agno/document/reader/pdf_reader.py +0 -219
  605. agno/document/reader/s3/pdf_reader.py +0 -46
  606. agno/document/reader/s3/text_reader.py +0 -51
  607. agno/document/reader/text_reader.py +0 -41
  608. agno/document/reader/website_reader.py +0 -175
  609. agno/document/reader/youtube_reader.py +0 -50
  610. agno/embedder/__init__.py +0 -1
  611. agno/embedder/azure_openai.py +0 -86
  612. agno/embedder/cohere.py +0 -72
  613. agno/embedder/fastembed.py +0 -37
  614. agno/embedder/google.py +0 -73
  615. agno/embedder/huggingface.py +0 -54
  616. agno/embedder/mistral.py +0 -80
  617. agno/embedder/ollama.py +0 -57
  618. agno/embedder/openai.py +0 -74
  619. agno/embedder/sentence_transformer.py +0 -38
  620. agno/embedder/voyageai.py +0 -64
  621. agno/eval/perf.py +0 -201
  622. agno/file/__init__.py +0 -1
  623. agno/file/file.py +0 -16
  624. agno/file/local/csv.py +0 -32
  625. agno/file/local/txt.py +0 -19
  626. agno/infra/app.py +0 -240
  627. agno/infra/base.py +0 -144
  628. agno/infra/context.py +0 -20
  629. agno/infra/db_app.py +0 -52
  630. agno/infra/resource.py +0 -205
  631. agno/infra/resources.py +0 -55
  632. agno/knowledge/agent.py +0 -230
  633. agno/knowledge/arxiv.py +0 -22
  634. agno/knowledge/combined.py +0 -22
  635. agno/knowledge/csv.py +0 -28
  636. agno/knowledge/csv_url.py +0 -19
  637. agno/knowledge/document.py +0 -20
  638. agno/knowledge/docx.py +0 -30
  639. agno/knowledge/json.py +0 -28
  640. agno/knowledge/langchain.py +0 -71
  641. agno/knowledge/llamaindex.py +0 -66
  642. agno/knowledge/pdf.py +0 -28
  643. agno/knowledge/pdf_url.py +0 -26
  644. agno/knowledge/s3/base.py +0 -60
  645. agno/knowledge/s3/pdf.py +0 -21
  646. agno/knowledge/s3/text.py +0 -23
  647. agno/knowledge/text.py +0 -30
  648. agno/knowledge/website.py +0 -88
  649. agno/knowledge/wikipedia.py +0 -31
  650. agno/knowledge/youtube.py +0 -22
  651. agno/memory/agent.py +0 -392
  652. agno/memory/classifier.py +0 -104
  653. agno/memory/db/__init__.py +0 -1
  654. agno/memory/db/base.py +0 -42
  655. agno/memory/db/mongodb.py +0 -189
  656. agno/memory/db/postgres.py +0 -203
  657. agno/memory/db/sqlite.py +0 -193
  658. agno/memory/memory.py +0 -15
  659. agno/memory/row.py +0 -36
  660. agno/memory/summarizer.py +0 -192
  661. agno/memory/summary.py +0 -19
  662. agno/memory/workflow.py +0 -38
  663. agno/models/google/gemini_openai.py +0 -26
  664. agno/models/ollama/hermes.py +0 -221
  665. agno/models/ollama/tools.py +0 -362
  666. agno/models/vertexai/gemini.py +0 -595
  667. agno/playground/__init__.py +0 -3
  668. agno/playground/async_router.py +0 -421
  669. agno/playground/deploy.py +0 -249
  670. agno/playground/operator.py +0 -92
  671. agno/playground/playground.py +0 -91
  672. agno/playground/schemas.py +0 -76
  673. agno/playground/serve.py +0 -55
  674. agno/playground/sync_router.py +0 -405
  675. agno/reasoning/agent.py +0 -68
  676. agno/run/response.py +0 -112
  677. agno/storage/agent/__init__.py +0 -0
  678. agno/storage/agent/base.py +0 -38
  679. agno/storage/agent/dynamodb.py +0 -350
  680. agno/storage/agent/json.py +0 -92
  681. agno/storage/agent/mongodb.py +0 -228
  682. agno/storage/agent/postgres.py +0 -367
  683. agno/storage/agent/session.py +0 -79
  684. agno/storage/agent/singlestore.py +0 -303
  685. agno/storage/agent/sqlite.py +0 -357
  686. agno/storage/agent/yaml.py +0 -93
  687. agno/storage/workflow/__init__.py +0 -0
  688. agno/storage/workflow/base.py +0 -40
  689. agno/storage/workflow/mongodb.py +0 -233
  690. agno/storage/workflow/postgres.py +0 -366
  691. agno/storage/workflow/session.py +0 -60
  692. agno/storage/workflow/sqlite.py +0 -359
  693. agno/tools/googlesearch.py +0 -88
  694. agno/utils/defaults.py +0 -57
  695. agno/utils/filesystem.py +0 -39
  696. agno/utils/git.py +0 -52
  697. agno/utils/json_io.py +0 -30
  698. agno/utils/load_env.py +0 -19
  699. agno/utils/py_io.py +0 -19
  700. agno/utils/pyproject.py +0 -18
  701. agno/utils/resource_filter.py +0 -31
  702. agno/vectordb/singlestore/s2vectordb.py +0 -390
  703. agno/vectordb/singlestore/s2vectordb2.py +0 -355
  704. agno/workspace/__init__.py +0 -0
  705. agno/workspace/config.py +0 -325
  706. agno/workspace/enums.py +0 -6
  707. agno/workspace/helpers.py +0 -48
  708. agno/workspace/operator.py +0 -758
  709. agno/workspace/settings.py +0 -63
  710. agno-0.1.2.dist-info/LICENSE +0 -375
  711. agno-0.1.2.dist-info/METADATA +0 -502
  712. agno-0.1.2.dist-info/RECORD +0 -352
  713. agno-0.1.2.dist-info/entry_points.txt +0 -3
  714. /agno/{cli → db/migrations}/__init__.py +0 -0
  715. /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
  716. /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
  717. /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
  718. /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
  719. /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
  720. /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
  721. /agno/{reranker → utils/models}/__init__.py +0 -0
  722. /agno/{storage → utils/print_response}/__init__.py +0 -0
  723. {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
@@ -1,25 +1,41 @@
1
1
  from dataclasses import dataclass
2
2
  from os import getenv
3
- from typing import Any, Dict, Iterator, List, Optional, Union
3
+ from typing import Any, AsyncIterator, Dict, Iterator, List, Optional, Type, Union
4
4
 
5
- from agno.models.base import Model, StreamData
5
+ from pydantic import BaseModel
6
+
7
+ from agno.exceptions import ModelProviderError
8
+ from agno.models.base import Model
6
9
  from agno.models.message import Message
7
- from agno.models.response import ModelResponse, ModelResponseEvent
8
- from agno.tools.function import FunctionCall
9
- from agno.utils.log import logger
10
- from agno.utils.timer import Timer
11
- from agno.utils.tools import get_function_call_for_tool_call
10
+ from agno.models.metrics import Metrics
11
+ from agno.models.response import ModelResponse
12
+ from agno.run.agent import RunOutput
13
+ from agno.utils.log import log_debug, log_error
14
+ from agno.utils.models.mistral import format_messages
12
15
 
13
16
  try:
17
+ from mistralai import CompletionEvent
14
18
  from mistralai import Mistral as MistralClient
15
- from mistralai.models import AssistantMessage, SystemMessage, ToolMessage, UserMessage
16
- from mistralai.models.chatcompletionresponse import ChatCompletionResponse
19
+ from mistralai.extra import response_format_from_pydantic_model
20
+ from mistralai.extra.struct_chat import ParsedChatCompletionResponse
21
+ from mistralai.models import (
22
+ AssistantMessage,
23
+ HTTPValidationError,
24
+ SDKError,
25
+ SystemMessage,
26
+ ToolMessage,
27
+ UserMessage,
28
+ )
29
+ from mistralai.models.chatcompletionresponse import (
30
+ ChatCompletionResponse,
31
+ )
17
32
  from mistralai.models.deltamessage import DeltaMessage
18
33
  from mistralai.types.basemodel import Unset
19
- except (ModuleNotFoundError, ImportError):
20
- raise ImportError("`mistralai` not installed. Please install using `pip install mistralai`")
21
34
 
22
- MistralMessage = Union[UserMessage, AssistantMessage, SystemMessage, ToolMessage]
35
+ MistralMessage = Union[UserMessage, AssistantMessage, SystemMessage, ToolMessage]
36
+
37
+ except ImportError:
38
+ raise ImportError("`mistralai` not installed. Please install using `pip install mistralai`")
23
39
 
24
40
 
25
41
  @dataclass
@@ -27,31 +43,15 @@ class MistralChat(Model):
27
43
  """
28
44
  MistralChat is a model that uses the Mistral API to generate responses to messages.
29
45
 
30
- Args:
31
- id (str): The ID of the model.
32
- name (str): The name of the model.
33
- provider (str): The provider of the model.
34
- temperature (Optional[float]): The temperature of the model.
35
- max_tokens (Optional[int]): The maximum number of tokens to generate.
36
- top_p (Optional[float]): The top p of the model.
37
- random_seed (Optional[int]): The random seed of the model.
38
- safe_mode (bool): The safe mode of the model.
39
- safe_prompt (bool): The safe prompt of the model.
40
- response_format (Optional[Union[Dict[str, Any], ChatCompletionResponse]]): The response format of the model.
41
- request_params (Optional[Dict[str, Any]]): The request parameters of the model.
42
- api_key (Optional[str]): The API key of the model.
43
- endpoint (Optional[str]): The endpoint of the model.
44
- max_retries (Optional[int]): The maximum number of retries of the model.
45
- timeout (Optional[int]): The timeout of the model.
46
- client_params (Optional[Dict[str, Any]]): The client parameters of the model.
47
- mistral_client (Optional[Mistral]): The Mistral client of the model.
48
-
46
+ For more information, see the Mistral API documentation: https://docs.mistral.ai/capabilities/completion/
49
47
  """
50
48
 
51
49
  id: str = "mistral-large-latest"
52
50
  name: str = "MistralChat"
53
51
  provider: str = "Mistral"
54
52
 
53
+ supports_native_structured_outputs: bool = True
54
+
55
55
  # -*- Request parameters
56
56
  temperature: Optional[float] = None
57
57
  max_tokens: Optional[int] = None
@@ -59,7 +59,6 @@ class MistralChat(Model):
59
59
  random_seed: Optional[int] = None
60
60
  safe_mode: bool = False
61
61
  safe_prompt: bool = False
62
- response_format: Optional[Union[Dict[str, Any], ChatCompletionResponse]] = None
63
62
  request_params: Optional[Dict[str, Any]] = None
64
63
  # -*- Client parameters
65
64
  api_key: Optional[str] = None
@@ -70,36 +69,51 @@ class MistralChat(Model):
70
69
  # -*- Provide the Mistral Client manually
71
70
  mistral_client: Optional[MistralClient] = None
72
71
 
73
- @property
74
- def client(self) -> MistralClient:
72
+ def get_client(self) -> MistralClient:
75
73
  """
76
74
  Get the Mistral client.
77
75
 
78
76
  Returns:
79
- MistralChat: The Mistral client.
77
+ MistralClient: The Mistral client instance.
80
78
  """
81
79
  if self.mistral_client:
82
80
  return self.mistral_client
83
81
 
82
+ _client_params = self._get_client_params()
83
+ self.mistral_client = MistralClient(**_client_params)
84
+ return self.mistral_client
85
+
86
+ def _get_client_params(self) -> Dict[str, Any]:
87
+ """
88
+ Get the client parameters for initializing Mistral clients.
89
+
90
+ Returns:
91
+ Dict[str, Any]: The client parameters.
92
+ """
93
+ client_params: Dict[str, Any] = {}
94
+
84
95
  self.api_key = self.api_key or getenv("MISTRAL_API_KEY")
85
96
  if not self.api_key:
86
- logger.error("MISTRAL_API_KEY not set. Please set the MISTRAL_API_KEY environment variable.")
87
-
88
- _client_params: Dict[str, Any] = {}
89
- if self.api_key:
90
- _client_params["api_key"] = self.api_key
91
- if self.endpoint:
92
- _client_params["endpoint"] = self.endpoint
93
- if self.max_retries:
94
- _client_params["max_retries"] = self.max_retries
95
- if self.timeout:
96
- _client_params["timeout"] = self.timeout
97
- if self.client_params:
98
- _client_params.update(self.client_params)
99
- return MistralClient(**_client_params)
100
-
101
- @property
102
- def api_kwargs(self) -> Dict[str, Any]:
97
+ log_error("MISTRAL_API_KEY not set. Please set the MISTRAL_API_KEY environment variable.")
98
+
99
+ client_params.update(
100
+ {
101
+ "api_key": self.api_key,
102
+ "endpoint": self.endpoint,
103
+ "max_retries": self.max_retries,
104
+ "timeout": self.timeout,
105
+ }
106
+ )
107
+
108
+ if self.client_params is not None:
109
+ client_params.update(self.client_params)
110
+
111
+ # Remove None values
112
+ return {k: v for k, v in client_params.items() if v is not None}
113
+
114
+ def get_request_params(
115
+ self, tools: Optional[List[Dict[str, Any]]] = None, tool_choice: Optional[Union[str, Dict[str, Any]]] = None
116
+ ) -> Dict[str, Any]:
103
117
  """
104
118
  Get the API kwargs for the Mistral model.
105
119
 
@@ -119,14 +133,17 @@ class MistralChat(Model):
119
133
  _request_params["safe_mode"] = self.safe_mode
120
134
  if self.safe_prompt:
121
135
  _request_params["safe_prompt"] = self.safe_prompt
122
- if self.tools:
123
- _request_params["tools"] = self.tools
124
- if self.tool_choice is None:
136
+ if tools:
137
+ _request_params["tools"] = tools
138
+ if tool_choice is None:
125
139
  _request_params["tool_choice"] = "auto"
126
140
  else:
127
- _request_params["tool_choice"] = self.tool_choice
141
+ _request_params["tool_choice"] = tool_choice
128
142
  if self.request_params:
129
143
  _request_params.update(self.request_params)
144
+
145
+ if _request_params:
146
+ log_debug(f"Calling {self.provider} with request parameters: {_request_params}", log_level=2)
130
147
  return _request_params
131
148
 
132
149
  def to_dict(self) -> Dict[str, Any]:
@@ -144,393 +161,276 @@ class MistralChat(Model):
144
161
  "random_seed": self.random_seed,
145
162
  "safe_mode": self.safe_mode,
146
163
  "safe_prompt": self.safe_prompt,
147
- "response_format": self.response_format,
148
164
  }
149
165
  )
150
166
  cleaned_dict = {k: v for k, v in _dict.items() if v is not None}
151
167
  return cleaned_dict
152
168
 
153
- def _prepare_messages(self, messages: List[Message]) -> List[MistralMessage]:
154
- mistral_messages: List[MistralMessage] = []
155
- for m in messages:
156
- mistral_message: MistralMessage
157
- if m.role == "user":
158
- mistral_message = UserMessage(role=m.role, content=m.content)
159
- elif m.role == "assistant":
160
- if m.tool_calls is not None:
161
- mistral_message = AssistantMessage(role=m.role, content=m.content, tool_calls=m.tool_calls)
162
- else:
163
- mistral_message = AssistantMessage(role=m.role, content=m.content)
164
- elif m.role == "system":
165
- mistral_message = SystemMessage(role=m.role, content=m.content)
166
- elif m.role == "tool":
167
- mistral_message = ToolMessage(name=m.name, content=m.content, tool_call_id=m.tool_call_id)
168
- else:
169
- raise ValueError(f"Unknown role: {m.role}")
170
- mistral_messages.append(mistral_message)
171
- return mistral_messages
172
-
173
- def invoke(self, messages: List[Message]) -> ChatCompletionResponse:
169
+ def invoke(
170
+ self,
171
+ messages: List[Message],
172
+ assistant_message: Message,
173
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
174
+ tools: Optional[List[Dict[str, Any]]] = None,
175
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
176
+ run_response: Optional[RunOutput] = None,
177
+ compress_tool_results: bool = False,
178
+ ) -> ModelResponse:
174
179
  """
175
180
  Send a chat completion request to the Mistral model.
181
+ """
182
+ mistral_messages = format_messages(messages, compress_tool_results)
183
+ try:
184
+ response: Union[ChatCompletionResponse, ParsedChatCompletionResponse]
185
+ if (
186
+ response_format is not None
187
+ and isinstance(response_format, type)
188
+ and issubclass(response_format, BaseModel)
189
+ ):
190
+ if run_response and run_response.metrics:
191
+ run_response.metrics.set_time_to_first_token()
176
192
 
177
- Args:
178
- messages (List[Message]): The messages to send to the model.
193
+ assistant_message.metrics.start_timer()
179
194
 
180
- Returns:
181
- ChatCompletionResponse: The response from the model.
182
- """
183
- mistral_messages = self._prepare_messages(messages)
184
- logger.debug(f"Mistral messages: {mistral_messages}")
185
- response = self.client.chat.complete(
186
- messages=mistral_messages,
187
- model=self.id,
188
- **self.api_kwargs,
189
- )
190
- if response is None:
191
- raise ValueError("Chat completion returned None")
192
- return response
195
+ response = self.get_client().chat.complete(
196
+ model=self.id,
197
+ messages=mistral_messages,
198
+ response_format=response_format_from_pydantic_model(response_format),
199
+ **self.get_request_params(tools=tools, tool_choice=tool_choice),
200
+ )
201
+ else:
202
+ if run_response and run_response.metrics:
203
+ run_response.metrics.set_time_to_first_token()
193
204
 
194
- def invoke_stream(self, messages: List[Message]) -> Iterator[Any]:
195
- """
196
- Stream the response from the Mistral model.
205
+ assistant_message.metrics.start_timer()
206
+ response = self.get_client().chat.complete(
207
+ model=self.id,
208
+ messages=mistral_messages,
209
+ **self.get_request_params(tools=tools, tool_choice=tool_choice),
210
+ )
197
211
 
198
- Args:
199
- messages (List[Message]): The messages to send to the model.
212
+ assistant_message.metrics.stop_timer()
200
213
 
201
- Returns:
202
- Iterator[Any]: The streamed response.
214
+ model_response = self._parse_provider_response(response, response_format=response_format)
215
+
216
+ return model_response
217
+
218
+ except HTTPValidationError as e:
219
+ log_error(f"HTTPValidationError from Mistral: {e}")
220
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
221
+ except SDKError as e:
222
+ log_error(f"SDKError from Mistral: {e}")
223
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
224
+
225
+ def invoke_stream(
226
+ self,
227
+ messages: List[Message],
228
+ assistant_message: Message,
229
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
230
+ tools: Optional[List[Dict[str, Any]]] = None,
231
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
232
+ run_response: Optional[RunOutput] = None,
233
+ compress_tool_results: bool = False,
234
+ ) -> Iterator[ModelResponse]:
203
235
  """
204
- mistral_messages = self._prepare_messages(messages)
205
- logger.debug(f"Mistral messages sending to stream endpoint: {mistral_messages}")
206
- response = self.client.chat.stream(
207
- messages=mistral_messages,
208
- model=self.id,
209
- **self.api_kwargs,
210
- )
211
- if response is None:
212
- raise ValueError("Chat stream returned None")
213
- # Since response is a generator, use 'yield from' to yield its items
214
- yield from response
215
-
216
- def _handle_tool_calls(
217
- self, assistant_message: Message, messages: List[Message], model_response: ModelResponse
218
- ) -> Optional[ModelResponse]:
236
+ Stream the response from the Mistral model.
219
237
  """
220
- Handle tool calls in the assistant message.
238
+ mistral_messages = format_messages(messages, compress_tool_results)
221
239
 
222
- Args:
223
- assistant_message (Message): The assistant message.
224
- messages (List[Message]): The messages to send to the model.
225
- model_response (ModelResponse): The model response.
240
+ if run_response and run_response.metrics:
241
+ run_response.metrics.set_time_to_first_token()
226
242
 
227
- Returns:
228
- Optional[ModelResponse]: The model response after handling tool calls.
243
+ assistant_message.metrics.start_timer()
244
+
245
+ try:
246
+ for chunk in self.get_client().chat.stream(
247
+ model=self.id,
248
+ messages=mistral_messages,
249
+ **self.get_request_params(tools=tools, tool_choice=tool_choice),
250
+ ):
251
+ yield self._parse_provider_response_delta(chunk)
252
+
253
+ assistant_message.metrics.stop_timer()
254
+
255
+ except HTTPValidationError as e:
256
+ log_error(f"HTTPValidationError from Mistral: {e}")
257
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
258
+ except SDKError as e:
259
+ log_error(f"SDKError from Mistral: {e}")
260
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
261
+
262
+ async def ainvoke(
263
+ self,
264
+ messages: List[Message],
265
+ assistant_message: Message,
266
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
267
+ tools: Optional[List[Dict[str, Any]]] = None,
268
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
269
+ run_response: Optional[RunOutput] = None,
270
+ compress_tool_results: bool = False,
271
+ ) -> ModelResponse:
229
272
  """
230
- if assistant_message.tool_calls is not None and len(assistant_message.tool_calls) > 0:
231
- if model_response.tool_calls is None:
232
- model_response.tool_calls = []
233
- model_response.content = ""
234
- tool_role: str = "tool"
235
- function_calls_to_run: List[FunctionCall] = []
236
- function_call_results: List[Message] = []
237
- for tool_call in assistant_message.tool_calls:
238
- tool_call["type"] = "function"
239
- _tool_call_id = tool_call.get("id")
240
- _function_call = get_function_call_for_tool_call(tool_call, self._functions)
241
- if _function_call is None:
242
- messages.append(
243
- Message(role="tool", tool_call_id=_tool_call_id, content="Could not find function to call.")
244
- )
245
- continue
246
- if _function_call.error is not None:
247
- messages.append(
248
- Message(
249
- role="tool", tool_call_id=_tool_call_id, tool_call_error=True, content=_function_call.error
250
- )
251
- )
252
- continue
253
- function_calls_to_run.append(_function_call)
254
-
255
- if self.show_tool_calls:
256
- if len(function_calls_to_run) == 1:
257
- model_response.content += f"\n - Running: {function_calls_to_run[0].get_call_str()}\n\n"
258
- elif len(function_calls_to_run) > 1:
259
- model_response.content += "\nRunning:"
260
- for _f in function_calls_to_run:
261
- model_response.content += f"\n - {_f.get_call_str()}"
262
- model_response.content += "\n\n"
263
-
264
- for function_call_response in self.run_function_calls(
265
- function_calls=function_calls_to_run, function_call_results=function_call_results, tool_role=tool_role
273
+ Send an asynchronous chat completion request to the Mistral API.
274
+ """
275
+ mistral_messages = format_messages(messages, compress_tool_results)
276
+ try:
277
+ response: Union[ChatCompletionResponse, ParsedChatCompletionResponse]
278
+ if (
279
+ response_format is not None
280
+ and isinstance(response_format, type)
281
+ and issubclass(response_format, BaseModel)
266
282
  ):
267
- if (
268
- function_call_response.event == ModelResponseEvent.tool_call_completed.value
269
- and function_call_response.tool_calls is not None
270
- ):
271
- model_response.tool_calls.extend(function_call_response.tool_calls)
283
+ if run_response and run_response.metrics:
284
+ run_response.metrics.set_time_to_first_token()
285
+ assistant_message.metrics.start_timer()
286
+ response = await self.get_client().chat.complete_async(
287
+ model=self.id,
288
+ messages=mistral_messages,
289
+ response_format=response_format_from_pydantic_model(response_format),
290
+ **self.get_request_params(tools=tools, tool_choice=tool_choice),
291
+ )
292
+ else:
293
+ if run_response and run_response.metrics:
294
+ run_response.metrics.set_time_to_first_token()
295
+ assistant_message.metrics.start_timer()
296
+ response = await self.get_client().chat.complete_async(
297
+ model=self.id,
298
+ messages=mistral_messages,
299
+ **self.get_request_params(tools=tools, tool_choice=tool_choice),
300
+ )
272
301
 
273
- if len(function_call_results) > 0:
274
- messages.extend(function_call_results)
302
+ assistant_message.metrics.stop_timer()
275
303
 
276
- return model_response
277
- return None
304
+ model_response = self._parse_provider_response(response, response_format=response_format)
278
305
 
279
- def _create_assistant_message(self, response: ChatCompletionResponse) -> Message:
306
+ return model_response
307
+ except HTTPValidationError as e:
308
+ log_error(f"HTTPValidationError from Mistral: {e}")
309
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
310
+ except SDKError as e:
311
+ log_error(f"SDKError from Mistral: {e}")
312
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
313
+
314
+ async def ainvoke_stream(
315
+ self,
316
+ messages: List[Message],
317
+ assistant_message: Message,
318
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
319
+ tools: Optional[List[Dict[str, Any]]] = None,
320
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
321
+ run_response: Optional[RunOutput] = None,
322
+ compress_tool_results: bool = False,
323
+ ) -> AsyncIterator[ModelResponse]:
280
324
  """
281
- Create an assistant message from the response.
282
-
283
- Args:
284
- response (ChatCompletionResponse): The response from the model.
285
-
286
- Returns:
287
- Message: The assistant message.
325
+ Stream an asynchronous response from the Mistral API.
288
326
  """
289
- if response.choices is None or len(response.choices) == 0:
290
- raise ValueError("The response does not contain any choices.")
327
+ mistral_messages = format_messages(messages, compress_tool_results)
328
+ try:
329
+ if run_response and run_response.metrics:
330
+ run_response.metrics.set_time_to_first_token()
291
331
 
292
- response_message: AssistantMessage = response.choices[0].message
332
+ assistant_message.metrics.start_timer()
293
333
 
294
- # Create assistant message
295
- assistant_message = Message(
296
- role=response_message.role or "assistant",
297
- content=response_message.content,
298
- )
334
+ async for chunk in await self.get_client().chat.stream_async(
335
+ model=self.id,
336
+ messages=mistral_messages,
337
+ **self.get_request_params(tools=tools, tool_choice=tool_choice),
338
+ ):
339
+ yield self._parse_provider_response_delta(chunk)
299
340
 
300
- if isinstance(response_message.tool_calls, list) and len(response_message.tool_calls) > 0:
301
- assistant_message.tool_calls = [t.model_dump() for t in response_message.tool_calls]
341
+ assistant_message.metrics.stop_timer()
302
342
 
303
- return assistant_message
343
+ except HTTPValidationError as e:
344
+ log_error(f"HTTPValidationError from Mistral: {e}")
345
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
346
+ except SDKError as e:
347
+ log_error(f"SDKError from Mistral: {e}")
348
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
304
349
 
305
- def _update_usage_metrics(
306
- self, assistant_message: Message, response: ChatCompletionResponse, response_timer: Timer
307
- ) -> None:
350
+ def _parse_provider_response(self, response: ChatCompletionResponse, **kwargs) -> ModelResponse:
308
351
  """
309
- Update the usage metrics for the response.
352
+ Parse the response from the Mistral model.
310
353
 
311
354
  Args:
312
- assistant_message (Message): The assistant message.
313
355
  response (ChatCompletionResponse): The response from the model.
314
- response_timer (Timer): The timer for the response.
315
356
  """
316
- # -*- Update usage metrics
317
- # Add response time to metrics
318
- assistant_message.metrics["time"] = response_timer.elapsed
319
- if "response_times" not in self.metrics:
320
- self.metrics["response_times"] = []
321
- self.metrics["response_times"].append(response_timer.elapsed)
322
- # Add token usage to metrics
323
- self.metrics.update(response.usage.model_dump())
324
-
325
- def response(self, messages: List[Message]) -> ModelResponse:
326
- """
327
- Send a chat completion request to the Mistral model.
328
-
329
- Args:
330
- messages (List[Message]): The messages to send to the model.
331
-
332
- Returns:
333
- ModelResponse: The response from the model.
334
- """
335
- logger.debug("---------- Mistral Response Start ----------")
336
- # -*- Log messages for debugging
337
- self._log_messages(messages)
338
357
  model_response = ModelResponse()
358
+ if response.choices is not None and len(response.choices) > 0:
359
+ response_message: AssistantMessage = response.choices[0].message
339
360
 
340
- response_timer = Timer()
341
- response_timer.start()
342
- response: ChatCompletionResponse = self.invoke(messages=messages)
343
- response_timer.stop()
344
- logger.debug(f"Time to generate response: {response_timer.elapsed:.4f}s")
345
-
346
- # -*- Ensure response.choices is not None
347
- if response.choices is None or len(response.choices) == 0:
348
- raise ValueError("Chat completion response has no choices")
349
-
350
- # -*- Create assistant message
351
- assistant_message = self._create_assistant_message(response)
352
-
353
- # -*- Update usage metrics
354
- self._update_usage_metrics(assistant_message, response, response_timer)
355
-
356
- # -*- Add assistant message to messages
357
- messages.append(assistant_message)
358
- assistant_message.log()
361
+ # -*- Set content
362
+ model_response.content = response_message.content # type: ignore
359
363
 
360
- # -*- Parse and run tool calls
361
- logger.debug(f"Functions: {self._functions}")
364
+ # -*- Set role
365
+ model_response.role = response_message.role
362
366
 
363
- # -*- Handle tool calls
364
- if self._handle_tool_calls(assistant_message, messages, model_response):
365
- response_after_tool_calls = self.response(messages=messages)
366
- if response_after_tool_calls.content is not None:
367
- if model_response.content is None:
368
- model_response.content = ""
369
- model_response.content += response_after_tool_calls.content
370
- return model_response
367
+ # -*- Set tool calls
368
+ if isinstance(response_message.tool_calls, list) and len(response_message.tool_calls) > 0:
369
+ model_response.tool_calls = []
370
+ for tool_call in response_message.tool_calls:
371
+ model_response.tool_calls.append(
372
+ {
373
+ "id": tool_call.id,
374
+ "type": "function",
375
+ "function": tool_call.function.model_dump(),
376
+ }
377
+ )
371
378
 
372
- # -*- Add content to model response
373
- if assistant_message.content is not None:
374
- model_response.content = assistant_message.get_content_string()
379
+ if response.usage is not None:
380
+ model_response.response_usage = self._get_metrics(response.usage)
375
381
 
376
- logger.debug("---------- Mistral Response End ----------")
377
382
  return model_response
378
383
 
379
- def _update_stream_metrics(self, stream_data: StreamData, assistant_message: Message):
384
+ def _parse_provider_response_delta(self, response_delta: CompletionEvent) -> ModelResponse:
380
385
  """
381
- Update the metrics for the streaming response.
382
-
383
- Args:
384
- stream_data (StreamData): The streaming data
385
- assistant_message (Message): The assistant message.
386
+ Parse the response delta from the Mistral model.
386
387
  """
387
- assistant_message.metrics["time"] = stream_data.response_timer.elapsed
388
- if stream_data.time_to_first_token is not None:
389
- assistant_message.metrics["time_to_first_token"] = stream_data.time_to_first_token
390
-
391
- if "response_times" not in self.metrics:
392
- self.metrics["response_times"] = []
393
- self.metrics["response_times"].append(stream_data.response_timer.elapsed)
394
- if stream_data.time_to_first_token is not None:
395
- if "time_to_first_token" not in self.metrics:
396
- self.metrics["time_to_first_token"] = []
397
- self.metrics["time_to_first_token"].append(stream_data.time_to_first_token)
398
-
399
- assistant_message.metrics["prompt_tokens"] = stream_data.response_prompt_tokens
400
- assistant_message.metrics["input_tokens"] = stream_data.response_prompt_tokens
401
- self.metrics["prompt_tokens"] = self.metrics.get("prompt_tokens", 0) + stream_data.response_prompt_tokens
402
- self.metrics["input_tokens"] = self.metrics.get("input_tokens", 0) + stream_data.response_prompt_tokens
403
-
404
- assistant_message.metrics["completion_tokens"] = stream_data.response_completion_tokens
405
- assistant_message.metrics["output_tokens"] = stream_data.response_completion_tokens
406
- self.metrics["completion_tokens"] = (
407
- self.metrics.get("completion_tokens", 0) + stream_data.response_completion_tokens
408
- )
409
- self.metrics["output_tokens"] = self.metrics.get("output_tokens", 0) + stream_data.response_completion_tokens
388
+ model_response = ModelResponse()
389
+
390
+ delta_message: DeltaMessage = response_delta.data.choices[0].delta
391
+ if delta_message.role is not None and not isinstance(delta_message.role, Unset):
392
+ model_response.role = delta_message.role # type: ignore
393
+
394
+ if (
395
+ delta_message.content is not None
396
+ and not isinstance(delta_message.content, Unset)
397
+ and isinstance(delta_message.content, str)
398
+ ):
399
+ model_response.content = delta_message.content
400
+
401
+ if delta_message.tool_calls is not None:
402
+ model_response.tool_calls = []
403
+ for tool_call in delta_message.tool_calls:
404
+ model_response.tool_calls.append(
405
+ {
406
+ "id": tool_call.id, # type: ignore
407
+ "type": "function",
408
+ "function": {
409
+ "name": tool_call.function.name, # type: ignore
410
+ "arguments": tool_call.function.arguments, # type: ignore
411
+ },
412
+ }
413
+ )
414
+
415
+ if response_delta.data.usage is not None:
416
+ model_response.response_usage = self._get_metrics(response_delta.data.usage)
410
417
 
411
- assistant_message.metrics["total_tokens"] = stream_data.response_total_tokens
412
- self.metrics["total_tokens"] = self.metrics.get("total_tokens", 0) + stream_data.response_total_tokens
418
+ return model_response
413
419
 
414
- def response_stream(self, messages: List[Message]) -> Iterator[ModelResponse]:
420
+ def _get_metrics(self, response_usage: Any) -> Metrics:
415
421
  """
416
- Stream the response from the Mistral model.
422
+ Parse the given Mistral usage into an Agno Metrics object.
417
423
 
418
424
  Args:
419
- messages (List[Message]): The messages to send to the model.
425
+ response_usage: Usage data from Mistral
420
426
 
421
427
  Returns:
422
- Iterator[ModelResponse]: The streamed response.
428
+ Metrics: Parsed metrics data
423
429
  """
424
- logger.debug("---------- Mistral Response Start ----------")
425
- # -*- Log messages for debugging
426
- self._log_messages(messages)
427
-
428
- stream_data: StreamData = StreamData()
429
- stream_data.response_timer.start()
430
-
431
- assistant_message_role = None
432
- for response in self.invoke_stream(messages=messages):
433
- # -*- Parse response
434
- response_delta: DeltaMessage = response.data.choices[0].delta
435
- if assistant_message_role is None and response_delta.role is not None:
436
- assistant_message_role = response_delta.role
437
-
438
- response_content: Optional[str] = None
439
- if (
440
- response_delta.content is not None
441
- and not isinstance(response_delta.content, Unset)
442
- and isinstance(response_delta.content, str)
443
- ):
444
- response_content = response_delta.content
445
- response_tool_calls = response_delta.tool_calls
446
-
447
- # -*- Return content if present, otherwise get tool call
448
- if response_content is not None:
449
- stream_data.response_content += response_content
450
- stream_data.completion_tokens += 1
451
- if stream_data.completion_tokens == 1:
452
- stream_data.time_to_first_token = stream_data.response_timer.elapsed
453
- logger.debug(f"Time to first token: {stream_data.time_to_first_token:.4f}s")
454
- yield ModelResponse(content=response_content)
455
-
456
- # -*- Parse tool calls
457
- if response_tool_calls is not None:
458
- if stream_data.response_tool_calls is None:
459
- stream_data.response_tool_calls = []
460
- stream_data.response_tool_calls.extend(response_tool_calls)
461
-
462
- stream_data.response_timer.stop()
463
- completion_tokens = stream_data.completion_tokens
464
- if completion_tokens > 0:
465
- logger.debug(f"Time per output token: {stream_data.response_timer.elapsed / completion_tokens:.4f}s")
466
- logger.debug(f"Throughput: {completion_tokens / stream_data.response_timer.elapsed:.4f} tokens/s")
467
-
468
- # -*- Create assistant message
469
- assistant_message = Message(role=(assistant_message_role or "assistant"))
470
- if stream_data.response_content != "":
471
- assistant_message.content = stream_data.response_content
472
-
473
- # -*- Add tool calls to assistant message
474
- if stream_data.response_tool_calls is not None:
475
- assistant_message.tool_calls = [t.model_dump() for t in stream_data.response_tool_calls]
476
-
477
- # -*- Update usage metrics
478
- self._update_stream_metrics(stream_data, assistant_message)
479
- messages.append(assistant_message)
480
- assistant_message.log()
481
-
482
- # -*- Parse and run tool calls
483
- if assistant_message.tool_calls is not None and len(assistant_message.tool_calls) > 0:
484
- tool_role: str = "tool"
485
- function_calls_to_run: List[FunctionCall] = []
486
- function_call_results: List[Message] = []
487
-
488
- for tool_call in assistant_message.tool_calls:
489
- _tool_call_id = tool_call.get("id")
490
- tool_call["type"] = "function"
491
- _function_call = get_function_call_for_tool_call(tool_call, self._functions)
492
- if _function_call is None:
493
- messages.append(
494
- Message(role="tool", tool_call_id=_tool_call_id, content="Could not find function to call.")
495
- )
496
- continue
497
- if _function_call.error is not None:
498
- messages.append(
499
- Message(
500
- role="tool", tool_call_id=_tool_call_id, tool_call_error=True, content=_function_call.error
501
- )
502
- )
503
- continue
504
- function_calls_to_run.append(_function_call)
505
-
506
- if self.show_tool_calls:
507
- if len(function_calls_to_run) == 1:
508
- yield ModelResponse(content=f"\n - Running: {function_calls_to_run[0].get_call_str()}\n\n")
509
- elif len(function_calls_to_run) > 1:
510
- yield ModelResponse(content="\nRunning:")
511
- for _f in function_calls_to_run:
512
- yield ModelResponse(content=f"\n - {_f.get_call_str()}")
513
- yield ModelResponse(content="\n\n")
514
-
515
- for intermediate_model_response in self.run_function_calls(
516
- function_calls=function_calls_to_run, function_call_results=function_call_results, tool_role=tool_role
517
- ):
518
- yield intermediate_model_response
519
-
520
- if len(function_call_results) > 0:
521
- messages.extend(function_call_results)
522
-
523
- yield from self.response_stream(messages=messages)
524
- logger.debug("---------- Mistral Response End ----------")
525
-
526
- async def ainvoke(self, *args, **kwargs) -> Any:
527
- raise NotImplementedError(f"Async not supported on {self.name}.")
528
-
529
- async def ainvoke_stream(self, *args, **kwargs) -> Any:
530
- raise NotImplementedError(f"Async not supported on {self.name}.")
430
+ metrics = Metrics()
531
431
 
532
- async def aresponse(self, messages: List[Message]) -> ModelResponse:
533
- raise NotImplementedError(f"Async not supported on {self.name}.")
432
+ metrics.input_tokens = response_usage.prompt_tokens or 0
433
+ metrics.output_tokens = response_usage.completion_tokens or 0
434
+ metrics.total_tokens = metrics.input_tokens + metrics.output_tokens
534
435
 
535
- async def aresponse_stream(self, messages: List[Message]) -> ModelResponse:
536
- raise NotImplementedError(f"Async not supported on {self.name}.")
436
+ return metrics