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,41 +1,37 @@
1
- import json
2
1
  from dataclasses import dataclass
3
2
  from os import getenv
4
- from typing import Any, Dict, Iterator, List, Optional, Tuple
3
+ from typing import Any, AsyncIterator, Dict, Iterator, List, Optional, Tuple, Type, Union
5
4
 
6
- from agno.models.base import Model, StreamData
5
+ import httpx
6
+ from pydantic import BaseModel
7
+
8
+ from agno.exceptions import ModelProviderError
9
+ from agno.models.base import Model
7
10
  from agno.models.message import Message
8
- from agno.models.response import ModelResponse, ModelResponseEvent
9
- from agno.tools.function import FunctionCall
10
- from agno.utils.log import logger
11
- from agno.utils.timer import Timer
12
- from agno.utils.tools import get_function_call_for_tool_call
11
+ from agno.models.metrics import Metrics
12
+ from agno.models.response import ModelResponse
13
+ from agno.run.agent import RunOutput
14
+ from agno.utils.http import get_default_async_client, get_default_sync_client
15
+ from agno.utils.log import log_debug, log_error, log_warning
16
+ from agno.utils.models.cohere import format_messages
13
17
 
14
18
  try:
15
- from cohere import Client as CohereClient
16
- from cohere.types.api_meta import ApiMeta
17
- from cohere.types.api_meta_tokens import ApiMetaTokens
18
- from cohere.types.non_streamed_chat_response import NonStreamedChatResponse
19
- from cohere.types.streamed_chat_response import (
20
- StreamedChatResponse,
21
- StreamEndStreamedChatResponse,
22
- StreamStartStreamedChatResponse,
23
- TextGenerationStreamedChatResponse,
24
- ToolCallsChunkStreamedChatResponse,
25
- ToolCallsGenerationStreamedChatResponse,
26
- )
27
- from cohere.types.tool import Tool as CohereTool
28
- from cohere.types.tool_call import ToolCall
29
- from cohere.types.tool_parameter_definitions_value import (
30
- ToolParameterDefinitionsValue,
31
- )
32
- from cohere.types.tool_result import ToolResult
33
- except (ModuleNotFoundError, ImportError):
19
+ from cohere import AsyncClientV2 as CohereAsyncClient
20
+ from cohere import ClientV2 as CohereClient
21
+ from cohere.v2.types.v2chat_response import V2ChatResponse
22
+ from cohere.v2.types.v2chat_stream_response import V2ChatStreamResponse
23
+ except ImportError:
34
24
  raise ImportError("`cohere` not installed. Please install using `pip install cohere`")
35
25
 
36
26
 
37
27
  @dataclass
38
28
  class Cohere(Model):
29
+ """
30
+ A class representing the Cohere model.
31
+
32
+ For more information, see: https://docs.cohere.com/docs/chat-api
33
+ """
34
+
39
35
  id: str = "command-r-plus"
40
36
  name: str = "cohere"
41
37
  provider: str = "Cohere"
@@ -45,565 +41,383 @@ class Cohere(Model):
45
41
  max_tokens: Optional[int] = None
46
42
  top_k: Optional[int] = None
47
43
  top_p: Optional[float] = None
44
+ seed: Optional[int] = None
48
45
  frequency_penalty: Optional[float] = None
49
46
  presence_penalty: Optional[float] = None
47
+ logprobs: Optional[bool] = None
50
48
  request_params: Optional[Dict[str, Any]] = None
49
+ strict_tools: bool = False
51
50
  # Add chat history to the cohere messages instead of using the conversation_id
52
51
  add_chat_history: bool = False
53
52
  # -*- Client parameters
54
53
  api_key: Optional[str] = None
55
54
  client_params: Optional[Dict[str, Any]] = None
55
+ http_client: Optional[Union[httpx.Client, httpx.AsyncClient]] = None
56
56
  # -*- Provide the Cohere client manually
57
- cohere_client: Optional[CohereClient] = None
57
+ client: Optional[CohereClient] = None
58
+ async_client: Optional[CohereAsyncClient] = None
58
59
 
59
60
  def get_client(self) -> CohereClient:
60
- if self.cohere_client:
61
- return self.cohere_client
61
+ if self.client:
62
+ return self.client
62
63
 
63
64
  _client_params: Dict[str, Any] = {}
64
65
 
65
66
  self.api_key = self.api_key or getenv("CO_API_KEY")
66
67
  if not self.api_key:
67
- logger.error("CO_API_KEY not set. Please set the CO_API_KEY environment variable.")
68
+ log_error("CO_API_KEY not set. Please set the CO_API_KEY environment variable.")
69
+
70
+ _client_params["api_key"] = self.api_key
71
+
72
+ if self.http_client:
73
+ if isinstance(self.http_client, httpx.Client):
74
+ _client_params["httpx_client"] = self.http_client
75
+ else:
76
+ log_warning("http_client is not an instance of httpx.Client. Using default global httpx.Client.")
77
+ # Use global sync client when user http_client is invalid
78
+ _client_params["httpx_client"] = get_default_sync_client()
79
+ else:
80
+ # Use global sync client when no custom http_client is provided
81
+ _client_params["httpx_client"] = get_default_sync_client()
82
+
83
+ self.client = CohereClient(**_client_params)
84
+ return self.client # type: ignore
68
85
 
69
- if self.api_key:
70
- _client_params["api_key"] = self.api_key
71
- return CohereClient(**_client_params)
86
+ def get_async_client(self) -> CohereAsyncClient:
87
+ if self.async_client:
88
+ return self.async_client
72
89
 
73
- @property
74
- def request_kwargs(self) -> Dict[str, Any]:
90
+ _client_params: Dict[str, Any] = {}
91
+
92
+ self.api_key = self.api_key or getenv("CO_API_KEY")
93
+
94
+ if not self.api_key:
95
+ raise ModelProviderError(
96
+ message="CO_API_KEY not set. Please set the CO_API_KEY environment variable.",
97
+ model_name=self.name,
98
+ model_id=self.id,
99
+ )
100
+
101
+ _client_params["api_key"] = self.api_key
102
+
103
+ if self.http_client:
104
+ if isinstance(self.http_client, httpx.AsyncClient):
105
+ _client_params["httpx_client"] = self.http_client
106
+ else:
107
+ log_warning(
108
+ "http_client is not an instance of httpx.AsyncClient. Using default global httpx.AsyncClient."
109
+ )
110
+ # Use global async client when user http_client is invalid
111
+ _client_params["httpx_client"] = get_default_async_client()
112
+ else:
113
+ # Use global async client when no custom http_client is provided
114
+ _client_params["httpx_client"] = get_default_async_client()
115
+ self.async_client = CohereAsyncClient(**_client_params)
116
+ return self.async_client # type: ignore
117
+
118
+ def get_request_params(
119
+ self,
120
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
121
+ tools: Optional[List[Dict[str, Any]]] = None,
122
+ ) -> Dict[str, Any]:
75
123
  _request_params: Dict[str, Any] = {}
76
- if self.session_id is not None and not self.add_chat_history:
77
- _request_params["conversation_id"] = self.session_id
78
124
  if self.temperature:
79
125
  _request_params["temperature"] = self.temperature
80
126
  if self.max_tokens:
81
127
  _request_params["max_tokens"] = self.max_tokens
82
128
  if self.top_k:
83
- _request_params["top_k"] = self.top_k
129
+ _request_params["k"] = self.top_k
84
130
  if self.top_p:
85
- _request_params["top_p"] = self.top_p
131
+ _request_params["p"] = self.top_p
132
+ if self.seed:
133
+ _request_params["seed"] = self.seed
134
+ if self.logprobs:
135
+ _request_params["logprobs"] = self.logprobs
86
136
  if self.frequency_penalty:
87
137
  _request_params["frequency_penalty"] = self.frequency_penalty
88
138
  if self.presence_penalty:
89
139
  _request_params["presence_penalty"] = self.presence_penalty
90
- if self.request_params:
91
- _request_params.update(self.request_params)
92
- return _request_params
93
140
 
94
- def _get_tools(self) -> Optional[List[CohereTool]]:
95
- """
96
- Get the tools in the format supported by the Cohere API.
97
-
98
- Returns:
99
- Optional[List[CohereTool]]: The list of tools.
100
- """
101
- if not self._functions:
102
- return None
103
-
104
- # Returns the tools in the format supported by the Cohere API
105
- return [
106
- CohereTool(
107
- name=f_name,
108
- description=function.description or "",
109
- parameter_definitions={
110
- param_name: ToolParameterDefinitionsValue(
111
- type=param_info["type"] if isinstance(param_info["type"], str) else param_info["type"][0],
112
- required="null" not in param_info["type"],
113
- )
114
- for param_name, param_info in function.parameters.get("properties", {}).items()
115
- },
116
- )
117
- for f_name, function in self._functions.items()
118
- ]
119
-
120
- def _prepare_for_invoke(
121
- self, messages: List[Message], tool_results: Optional[List[ToolResult]] = None
122
- ) -> Tuple[str, Dict[str, Any]]:
123
- api_kwargs: Dict[str, Any] = self.request_kwargs
124
- chat_message: str = ""
125
-
126
- if self.add_chat_history:
127
- logger.debug("Providing chat_history to cohere")
128
- chat_history: List = []
129
- for m in messages:
130
- if m.role == "system" and "preamble" not in api_kwargs:
131
- api_kwargs["preamble"] = m.content
132
- elif m.role == "user":
133
- # Update the chat_message to the new user message
134
- chat_message = m.get_content_string()
135
- chat_history.append({"role": "USER", "message": chat_message})
141
+ if response_format:
142
+ _request_params["response_format"] = response_format
143
+
144
+ # Format tools
145
+ if tools is not None and len(tools) > 0:
146
+ formatted_tools = []
147
+ for tool in tools:
148
+ if tool.get("type") == "function" and "function" in tool:
149
+ # Extract only the fields that Cohere supports
150
+ filtered_tool = {
151
+ "type": "function",
152
+ "function": {
153
+ "name": tool["function"]["name"],
154
+ "description": tool["function"]["description"],
155
+ "parameters": tool["function"]["parameters"],
156
+ },
157
+ }
158
+ formatted_tools.append(filtered_tool)
136
159
  else:
137
- chat_history.append({"role": "CHATBOT", "message": m.get_content_string() or ""})
138
- if chat_history[-1].get("role") == "USER":
139
- chat_history.pop()
140
- api_kwargs["chat_history"] = chat_history
141
- else:
142
- # Set first system message as preamble
143
- for m in messages:
144
- if m.role == "system" and "preamble" not in api_kwargs:
145
- api_kwargs["preamble"] = m.get_content_string()
146
- break
147
- # Set last user message as chat_message
148
- for m in reversed(messages):
149
- if m.role == "user":
150
- chat_message = m.get_content_string()
151
- break
152
-
153
- if self.tools:
154
- api_kwargs["tools"] = self._get_tools()
160
+ # For non-function tools, pass them through as-is
161
+ formatted_tools.append(tool)
162
+
163
+ _request_params["tools"] = formatted_tools
164
+ # Fix optional parameters where the "type" is [type, null]
165
+ for tool in _request_params["tools"]: # type: ignore
166
+ if "parameters" in tool["function"] and "properties" in tool["function"]["parameters"]: # type: ignore
167
+ params = tool["function"]["parameters"]
168
+ # Cohere requires at least one required parameter, so if unset, set it to all parameters
169
+ if len(params.get("required", [])) == 0:
170
+ params["required"] = list(params["properties"].keys())
171
+ _request_params["strict_tools"] = self.strict_tools
155
172
 
156
- if tool_results:
157
- api_kwargs["tool_results"] = tool_results
173
+ if self.request_params:
174
+ _request_params.update(self.request_params)
158
175
 
159
- return chat_message, api_kwargs
176
+ if _request_params:
177
+ log_debug(f"Calling {self.provider} with request parameters: {_request_params}", log_level=2)
178
+ return _request_params
160
179
 
161
180
  def invoke(
162
- self, messages: List[Message], tool_results: Optional[List[ToolResult]] = None
163
- ) -> NonStreamedChatResponse:
181
+ self,
182
+ messages: List[Message],
183
+ assistant_message: Message,
184
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
185
+ tools: Optional[List[Dict[str, Any]]] = None,
186
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
187
+ run_response: Optional[RunOutput] = None,
188
+ compress_tool_results: bool = False,
189
+ ) -> ModelResponse:
164
190
  """
165
191
  Invoke a non-streamed chat response from the Cohere API.
192
+ """
193
+ request_kwargs = self.get_request_params(response_format=response_format, tools=tools)
166
194
 
167
- Args:
168
- messages (List[Message]): The list of messages.
169
- tool_results (Optional[List[ToolResult]]): The list of tool results.
195
+ try:
196
+ if run_response and run_response.metrics:
197
+ run_response.metrics.set_time_to_first_token()
170
198
 
171
- Returns:
172
- NonStreamedChatResponse: The non-streamed chat response.
173
- """
174
- chat_message, api_kwargs = self._prepare_for_invoke(messages, tool_results)
199
+ assistant_message.metrics.start_timer()
200
+ provider_response = self.get_client().chat(
201
+ model=self.id,
202
+ messages=format_messages(messages, compress_tool_results), # type: ignore
203
+ **request_kwargs,
204
+ ) # type: ignore
205
+ assistant_message.metrics.stop_timer()
206
+
207
+ model_response = self._parse_provider_response(provider_response, response_format=response_format)
208
+
209
+ return model_response
175
210
 
176
- return self.get_client().chat(model=self.id, message=chat_message, **api_kwargs)
211
+ except Exception as e:
212
+ log_error(f"Unexpected error calling Cohere API: {str(e)}")
213
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
177
214
 
178
215
  def invoke_stream(
179
- self, messages: List[Message], tool_results: Optional[List[ToolResult]] = None
180
- ) -> Iterator[StreamedChatResponse]:
216
+ self,
217
+ messages: List[Message],
218
+ assistant_message: Message,
219
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
220
+ tools: Optional[List[Dict[str, Any]]] = None,
221
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
222
+ run_response: Optional[RunOutput] = None,
223
+ compress_tool_results: bool = False,
224
+ ) -> Iterator[ModelResponse]:
181
225
  """
182
226
  Invoke a streamed chat response from the Cohere API.
227
+ """
228
+ request_kwargs = self.get_request_params(response_format=response_format, tools=tools)
183
229
 
184
- Args:
185
- messages (List[Message]): The list of messages.
186
- tool_results (Optional[List[ToolResult]]): The list of tool results.
230
+ try:
231
+ if run_response and run_response.metrics:
232
+ run_response.metrics.set_time_to_first_token()
187
233
 
188
- Returns:
189
- Iterator[StreamedChatResponse]: An iterator of streamed chat responses.
190
- """
191
- chat_message, api_kwargs = self._prepare_for_invoke(messages, tool_results)
234
+ tool_use: Dict[str, Any] = {}
192
235
 
193
- return self.get_client().chat_stream(model=self.id, message=chat_message, **api_kwargs)
236
+ assistant_message.metrics.start_timer()
194
237
 
195
- def _prepare_function_calls(self, agent_message: Message) -> Tuple[List[FunctionCall], List[Message]]:
196
- """
197
- Prepares function calls based on tool calls in the agent message.
238
+ for response in self.get_client().chat_stream(
239
+ model=self.id,
240
+ messages=format_messages(messages, compress_tool_results), # type: ignore
241
+ **request_kwargs,
242
+ ):
243
+ model_response, tool_use = self._parse_provider_response_delta(response, tool_use=tool_use)
244
+ yield model_response
198
245
 
199
- This method processes tool calls, matches them with available functions,
200
- and prepares them for execution. It also handles errors if functions
201
- are not found or if there are issues with the function calls.
246
+ assistant_message.metrics.stop_timer()
202
247
 
203
- Args:
204
- agent_message (Message): The message containing tool calls to process.
248
+ except Exception as e:
249
+ log_error(f"Unexpected error calling Cohere API: {str(e)}")
250
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
205
251
 
206
- Returns:
207
- Tuple[List[FunctionCall], List[Message]]: A tuple containing a list of
208
- prepared function calls and a list of error messages.
252
+ async def ainvoke(
253
+ self,
254
+ messages: List[Message],
255
+ assistant_message: Message,
256
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
257
+ tools: Optional[List[Dict[str, Any]]] = None,
258
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
259
+ run_response: Optional[RunOutput] = None,
260
+ compress_tool_results: bool = False,
261
+ ) -> ModelResponse:
209
262
  """
210
- function_calls_to_run: List[FunctionCall] = []
211
- error_messages: List[Message] = []
212
-
213
- # Check if tool_calls is None or empty
214
- if not agent_message.tool_calls:
215
- return function_calls_to_run, error_messages
263
+ Asynchronously invoke a non-streamed chat response from the Cohere API.
264
+ """
265
+ request_kwargs = self.get_request_params(response_format=response_format, tools=tools)
216
266
 
217
- # Process each tool call in the agent message
218
- for tool_call in agent_message.tool_calls:
219
- # Attempt to get a function call for the tool call
220
- _function_call = get_function_call_for_tool_call(tool_call, self._functions)
267
+ try:
268
+ if run_response and run_response.metrics:
269
+ run_response.metrics.set_time_to_first_token()
221
270
 
222
- # Handle cases where function call cannot be created
223
- if _function_call is None:
224
- error_messages.append(Message(role="user", content="Could not find function to call."))
225
- continue
271
+ assistant_message.metrics.start_timer()
272
+ provider_response = await self.get_async_client().chat(
273
+ model=self.id,
274
+ messages=format_messages(messages, compress_tool_results), # type: ignore
275
+ **request_kwargs,
276
+ )
277
+ assistant_message.metrics.stop_timer()
226
278
 
227
- # Handle cases where function call has an error
228
- if _function_call.error is not None:
229
- error_messages.append(Message(role="user", content=_function_call.error))
230
- continue
279
+ model_response = self._parse_provider_response(provider_response, response_format=response_format)
231
280
 
232
- # Add valid function calls to the list
233
- function_calls_to_run.append(_function_call)
281
+ return model_response
234
282
 
235
- return function_calls_to_run, error_messages
283
+ except Exception as e:
284
+ log_error(f"Unexpected error calling Cohere API: {str(e)}")
285
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
236
286
 
237
- def _handle_tool_calls(
287
+ async def ainvoke_stream(
238
288
  self,
239
- assistant_message: Message,
240
289
  messages: List[Message],
241
- response_tool_calls: Optional[List[ToolCall]],
242
- model_response: ModelResponse,
243
- ) -> Optional[Any]:
290
+ assistant_message: Message,
291
+ response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
292
+ tools: Optional[List[Dict[str, Any]]] = None,
293
+ tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
294
+ run_response: Optional[RunOutput] = None,
295
+ compress_tool_results: bool = False,
296
+ ) -> AsyncIterator[ModelResponse]:
244
297
  """
245
- Handle tool calls in the assistant message.
246
-
247
- Args:
248
- assistant_message (Message): The assistant message.
249
- messages (List[Message]): The list of messages.
250
- response_tool_calls (List[Any]): The list of response tool calls.
251
- model_response (ModelResponse): The model response.
252
-
253
- Returns:
254
- Optional[Any]: The tool results.
298
+ Asynchronously invoke a streamed chat response from the Cohere API.
255
299
  """
300
+ request_kwargs = self.get_request_params(response_format=response_format, tools=tools)
256
301
 
257
- model_response.content = ""
258
- tool_role: str = "tool"
259
- function_calls_to_run: List[FunctionCall] = []
260
- function_call_results: List[Message] = []
261
- if assistant_message.tool_calls is None:
262
- return None
263
-
264
- if model_response.tool_calls is None:
265
- model_response.tool_calls = []
266
-
267
- for tool_call in assistant_message.tool_calls:
268
- _tool_call_id = tool_call.get("id")
269
- _function_call = get_function_call_for_tool_call(tool_call, self._functions)
270
- if _function_call is None:
271
- messages.append(
272
- Message(
273
- role="tool",
274
- tool_call_id=_tool_call_id,
275
- content="Could not find function to call.",
276
- )
277
- )
278
- continue
279
- if _function_call.error is not None:
280
- messages.append(
281
- Message(
282
- role="tool",
283
- tool_call_id=_tool_call_id,
284
- content=_function_call.error,
285
- )
286
- )
287
- continue
288
- function_calls_to_run.append(_function_call)
289
-
290
- model_response.content = assistant_message.get_content_string() + "\n\n"
302
+ try:
303
+ if run_response and run_response.metrics:
304
+ run_response.metrics.set_time_to_first_token()
291
305
 
292
- if self.show_tool_calls:
293
- model_response.content += "\nRunning:"
294
- for _f in function_calls_to_run:
295
- model_response.content += f"\n - {_f.get_call_str()}"
296
- model_response.content += "\n\n"
306
+ tool_use: Dict[str, Any] = {}
297
307
 
298
- function_calls_to_run, error_messages = self._prepare_function_calls(assistant_message)
308
+ assistant_message.metrics.start_timer()
299
309
 
300
- for function_call_response in self.run_function_calls(
301
- function_calls=function_calls_to_run, function_call_results=function_call_results, tool_role=tool_role
302
- ):
303
- if (
304
- function_call_response.event == ModelResponseEvent.tool_call_completed.value
305
- and function_call_response.tool_calls is not None
310
+ async for response in self.get_async_client().chat_stream(
311
+ model=self.id,
312
+ messages=format_messages(messages, compress_tool_results), # type: ignore
313
+ **request_kwargs,
306
314
  ):
307
- model_response.tool_calls.extend(function_call_response.tool_calls)
315
+ model_response, tool_use = self._parse_provider_response_delta(response, tool_use=tool_use)
316
+ yield model_response
308
317
 
309
- if len(function_call_results) > 0:
310
- messages.extend(function_call_results)
311
-
312
- # Prepare tool results for the next API call
313
- if response_tool_calls:
314
- tool_results = [
315
- ToolResult(
316
- call=tool_call,
317
- outputs=[tool_call.parameters, {"result": fn_result.content}],
318
- )
319
- for tool_call, fn_result in zip(response_tool_calls, function_call_results)
320
- ]
321
- else:
322
- tool_results = None
318
+ assistant_message.metrics.stop_timer()
323
319
 
324
- return tool_results
320
+ except Exception as e:
321
+ log_error(f"Unexpected error calling Cohere API: {str(e)}")
322
+ raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
325
323
 
326
- def _create_assistant_message(self, response: NonStreamedChatResponse) -> Message:
324
+ def _parse_provider_response(self, response: V2ChatResponse, **kwargs) -> ModelResponse:
327
325
  """
328
- Create an assistant message from the response.
326
+ Parse the model provider response.
329
327
 
330
328
  Args:
331
- response (NonStreamedChatResponse): The response from the Cohere API.
332
-
333
- Returns:
334
- Message: The assistant message.
335
- """
336
- response_content = response.text
337
- return Message(role="assistant", content=response_content)
338
-
339
- def response(self, messages: List[Message], tool_results: Optional[List[ToolResult]] = None) -> ModelResponse:
340
- """
341
- Send a chat completion request to the Cohere API.
342
-
343
- Args:
344
- messages (List[Message]): A list of message objects representing the conversation.
345
-
346
- Returns:
347
- ModelResponse: The model response from the API.
329
+ response (V2ChatResponse): The response from the Cohere API.
348
330
  """
349
- logger.debug("---------- Cohere Response Start ----------")
350
- self._log_messages(messages)
351
331
  model_response = ModelResponse()
352
332
 
353
- # Timer for response
354
- response_timer = Timer()
355
- response_timer.start()
356
- logger.debug(f"Tool Results: {tool_results}")
357
- response: NonStreamedChatResponse = self.invoke(messages=messages, tool_results=tool_results)
358
- response_timer.stop()
359
- logger.debug(f"Time to generate response: {response_timer.elapsed:.4f}s")
360
-
361
- assistant_message = self._create_assistant_message(response)
362
-
363
- # Process tool calls if present
364
- response_tool_calls = response.tool_calls
365
- if response_tool_calls:
366
- tool_calls = [
367
- {
368
- "type": "function",
369
- "function": {
370
- "name": tools.name,
371
- "arguments": json.dumps(tools.parameters),
372
- },
373
- }
374
- for tools in response_tool_calls
375
- ]
376
- assistant_message.tool_calls = tool_calls
377
-
378
- # Handle tool calls if present and tool running is enabled
379
- if assistant_message.tool_calls:
380
- tool_results = self._handle_tool_calls(
381
- assistant_message=assistant_message,
382
- messages=messages,
383
- response_tool_calls=response_tool_calls,
384
- model_response=model_response,
385
- )
333
+ model_response.role = response.message.role
386
334
 
387
- # Make a recursive call with tool results if available
388
- if tool_results:
389
- # Cohere doesn't allow tool calls in the same message as the user's message, so we add a new user message with empty content
390
- messages.append(Message(role="user", content=""))
335
+ response_message = response.message
336
+ if response_message.content is not None:
337
+ full_content = ""
338
+ for item in response_message.content:
339
+ if hasattr(item, "text") and item.text is not None: # type: ignore
340
+ full_content += item.text # type: ignore
341
+ model_response.content = full_content
391
342
 
392
- response_after_tool_calls = self.response(messages=messages, tool_results=tool_results)
393
- if response_after_tool_calls.content:
394
- if model_response.content is None:
395
- model_response.content = ""
396
- model_response.content += response_after_tool_calls.content
397
- return model_response
343
+ if response_message.tool_calls is not None:
344
+ model_response.tool_calls = [t.model_dump() for t in response_message.tool_calls]
398
345
 
399
- # If no tool calls, return the agent message content
400
- if assistant_message.content:
401
- model_response.content = assistant_message.get_content_string()
346
+ if response.usage is not None:
347
+ model_response.response_usage = self._get_metrics(response.usage)
402
348
 
403
- logger.debug("---------- Cohere Response End ----------")
404
349
  return model_response
405
350
 
406
- def _update_stream_metrics(self, stream_data: StreamData, assistant_message: Message):
351
+ def _parse_provider_response_delta(
352
+ self, response: V2ChatStreamResponse, tool_use: Dict[str, Any]
353
+ ) -> Tuple[ModelResponse, Dict[str, Any]]: # type: ignore
407
354
  """
408
- Update the metrics for the streaming response.
355
+ Parse the streaming response from the model provider into ModelResponse objects.
409
356
 
410
357
  Args:
411
- stream_data (StreamData): The streaming data
412
- assistant_message (Message): The assistant message.
358
+ response: Raw response chunk from the model provider
359
+
360
+ Returns:
361
+ ModelResponse: Parsed response delta
413
362
  """
414
- assistant_message.metrics["time"] = stream_data.response_timer.elapsed
415
- if stream_data.time_to_first_token is not None:
416
- assistant_message.metrics["time_to_first_token"] = stream_data.time_to_first_token
417
-
418
- if "response_times" not in self.metrics:
419
- self.metrics["response_times"] = []
420
- self.metrics["response_times"].append(stream_data.response_timer.elapsed)
421
- if stream_data.time_to_first_token is not None:
422
- if "time_to_first_token" not in self.metrics:
423
- self.metrics["time_to_first_token"] = []
424
- self.metrics["time_to_first_token"].append(stream_data.time_to_first_token)
425
- if stream_data.completion_tokens > 0:
426
- if "tokens_per_second" not in self.metrics:
427
- self.metrics["tokens_per_second"] = []
428
- self.metrics["tokens_per_second"].append(
429
- f"{stream_data.completion_tokens / stream_data.response_timer.elapsed:.4f}"
430
- )
363
+ model_response = ModelResponse()
431
364
 
432
- assistant_message.metrics["prompt_tokens"] = stream_data.response_prompt_tokens
433
- assistant_message.metrics["input_tokens"] = stream_data.response_prompt_tokens
434
- self.metrics["prompt_tokens"] = self.metrics.get("prompt_tokens", 0) + stream_data.response_prompt_tokens
435
- self.metrics["input_tokens"] = self.metrics.get("input_tokens", 0) + stream_data.response_prompt_tokens
365
+ # 1. Add content
366
+ if (
367
+ response.type == "content-delta"
368
+ and response.delta is not None
369
+ and response.delta.message is not None
370
+ and response.delta.message.content is not None
371
+ and response.delta.message.content.text is not None
372
+ ):
373
+ model_response.content = response.delta.message.content.text
436
374
 
437
- assistant_message.metrics["completion_tokens"] = stream_data.response_completion_tokens
438
- assistant_message.metrics["output_tokens"] = stream_data.response_completion_tokens
439
- self.metrics["completion_tokens"] = (
440
- self.metrics.get("completion_tokens", 0) + stream_data.response_completion_tokens
441
- )
442
- self.metrics["output_tokens"] = self.metrics.get("output_tokens", 0) + stream_data.response_completion_tokens
375
+ # 2. Add tool calls information
443
376
 
444
- assistant_message.metrics["total_tokens"] = stream_data.response_total_tokens
445
- self.metrics["total_tokens"] = self.metrics.get("total_tokens", 0) + stream_data.response_total_tokens
377
+ # 2.1 Add starting tool call
378
+ elif response.type == "tool-call-start" and response.delta is not None:
379
+ if response.delta.message is not None and response.delta.message.tool_calls is not None:
380
+ tool_use = response.delta.message.tool_calls.model_dump()
446
381
 
447
- def response_stream(
448
- self, messages: List[Message], tool_results: Optional[List[ToolResult]] = None
449
- ) -> Iterator[ModelResponse]:
450
- logger.debug("---------- Cohere Response Start ----------")
451
- # -*- Log messages for debugging
452
- self._log_messages(messages)
453
-
454
- stream_data: StreamData = StreamData()
455
- stream_data.response_timer.start()
456
-
457
- stream_data.response_content = ""
458
- tool_calls: List[Dict[str, Any]] = []
459
- stream_data.response_tool_calls = []
460
- last_delta: Optional[NonStreamedChatResponse] = None
461
-
462
- for response in self.invoke_stream(messages=messages, tool_results=tool_results):
463
- if isinstance(response, StreamStartStreamedChatResponse):
464
- pass
465
-
466
- if isinstance(response, TextGenerationStreamedChatResponse):
467
- if response.text is not None:
468
- stream_data.response_content += response.text
469
- stream_data.completion_tokens += 1
470
- if stream_data.completion_tokens == 1:
471
- stream_data.time_to_first_token = stream_data.response_timer.elapsed
472
- logger.debug(f"Time to first token: {stream_data.time_to_first_token:.4f}s")
473
- yield ModelResponse(content=response.text)
474
-
475
- if isinstance(response, ToolCallsChunkStreamedChatResponse):
476
- if response.tool_call_delta is None:
477
- yield ModelResponse(content=response.text)
478
-
479
- # Detect if response is a tool call
480
- if isinstance(response, ToolCallsGenerationStreamedChatResponse):
481
- for tc in response.tool_calls:
482
- stream_data.response_tool_calls.append(tc)
483
- tool_calls.append(
484
- {
485
- "type": "function",
486
- "function": {
487
- "name": tc.name,
488
- "arguments": json.dumps(tc.parameters),
489
- },
490
- }
491
- )
492
-
493
- if isinstance(response, StreamEndStreamedChatResponse):
494
- last_delta = response.response
495
-
496
- yield ModelResponse(content="\n\n")
497
-
498
- stream_data.response_timer.stop()
499
- logger.debug(f"Time to generate response: {stream_data.response_timer.elapsed:.4f}s")
500
-
501
- # -*- Create assistant message
502
- assistant_message = Message(role="assistant", content=stream_data.response_content)
503
- # -*- Add tool calls to assistant message
504
- if len(stream_data.response_tool_calls) > 0:
505
- assistant_message.tool_calls = tool_calls
506
-
507
- # -*- Update usage metrics
508
- # Add response time to metrics
509
- assistant_message.metrics["time"] = stream_data.response_timer.elapsed
510
- if "response_times" not in self.metrics:
511
- self.metrics["response_times"] = []
512
- self.metrics["response_times"].append(stream_data.response_timer.elapsed)
513
-
514
- # Add token usage to metrics
515
- meta: Optional[ApiMeta] = last_delta.meta if last_delta else None
516
- tokens: Optional[ApiMetaTokens] = meta.tokens if meta else None
517
-
518
- if tokens:
519
- input_tokens = tokens.input_tokens
520
- output_tokens = tokens.output_tokens
521
-
522
- if input_tokens is not None:
523
- assistant_message.metrics["input_tokens"] = input_tokens
524
- self.metrics["input_tokens"] = self.metrics.get("input_tokens", 0) + input_tokens
525
-
526
- if output_tokens is not None:
527
- assistant_message.metrics["output_tokens"] = output_tokens
528
- self.metrics["output_tokens"] = self.metrics.get("output_tokens", 0) + output_tokens
529
-
530
- if input_tokens is not None and output_tokens is not None:
531
- assistant_message.metrics["total_tokens"] = input_tokens + output_tokens
532
- self.metrics["total_tokens"] = self.metrics.get("total_tokens", 0) + input_tokens + output_tokens
533
-
534
- # -*- Add assistant message to messages
535
- self._update_stream_metrics(stream_data=stream_data, assistant_message=assistant_message)
536
- messages.append(assistant_message)
537
- assistant_message.log()
538
- logger.debug(f"Assistant Message: {assistant_message}")
539
-
540
- # -*- Parse and run function call
541
- if assistant_message.tool_calls is not None and len(assistant_message.tool_calls) > 0:
542
- tool_role: str = "tool"
543
- function_calls_to_run: List[FunctionCall] = []
544
- function_call_results: List[Message] = []
545
- for tool_call in assistant_message.tool_calls:
546
- _tool_call_id = tool_call.get("id")
547
- _function_call = get_function_call_for_tool_call(tool_call, self._functions)
548
- if _function_call is None:
549
- messages.append(
550
- Message(
551
- role=tool_role,
552
- tool_call_id=_tool_call_id,
553
- content="Could not find function to call.",
554
- )
555
- )
556
- continue
557
- if _function_call.error is not None:
558
- messages.append(
559
- Message(
560
- role=tool_role,
561
- tool_call_id=_tool_call_id,
562
- content=_function_call.error,
563
- )
564
- )
565
- continue
566
- function_calls_to_run.append(_function_call)
567
-
568
- if self.show_tool_calls:
569
- if len(function_calls_to_run) == 1:
570
- yield ModelResponse(content=f"- Running: {function_calls_to_run[0].get_call_str()}\n\n")
571
- elif len(function_calls_to_run) > 1:
572
- yield ModelResponse(content="Running:")
573
- for _f in function_calls_to_run:
574
- yield ModelResponse(content=f"\n - {_f.get_call_str()}")
575
- yield ModelResponse(content="\n\n")
576
-
577
- for intermediate_model_response in self.run_function_calls(
578
- function_calls=function_calls_to_run, function_call_results=function_call_results, tool_role=tool_role
382
+ # 2.2 Add tool call delta
383
+ elif response.type == "tool-call-delta" and response.delta is not None:
384
+ if (
385
+ response.delta.message is not None
386
+ and response.delta.message.tool_calls is not None
387
+ and response.delta.message.tool_calls.function is not None
388
+ and response.delta.message.tool_calls.function.arguments is not None
579
389
  ):
580
- yield intermediate_model_response
581
-
582
- if len(function_call_results) > 0:
583
- messages.extend(function_call_results)
390
+ tool_use["function"]["arguments"] += response.delta.message.tool_calls.function.arguments
391
+
392
+ # 2.3 Add ending tool call
393
+ elif response.type == "tool-call-end":
394
+ model_response.tool_calls = [tool_use]
395
+
396
+ # 3. Add metrics
397
+ elif (
398
+ response.type == "message-end"
399
+ and response.delta is not None
400
+ and response.delta.usage is not None
401
+ and response.delta.usage.tokens is not None
402
+ ):
403
+ model_response.response_usage = self._get_metrics(response.delta.usage) # type: ignore
584
404
 
585
- # Making sure the length of tool calls and function call results are the same to avoid unexpected behavior
586
- if stream_data.response_tool_calls is not None:
587
- # Constructs a list named tool_results, where each element is a dictionary that contains details of tool calls and their outputs.
588
- # It pairs each tool call in response_tool_calls with its corresponding result in function_call_results.
589
- tool_results = [
590
- ToolResult(call=tool_call, outputs=[tool_call.parameters, {"result": fn_result.content}])
591
- for tool_call, fn_result in zip(stream_data.response_tool_calls, function_call_results)
592
- ]
593
- messages.append(Message(role="user", content=""))
405
+ return model_response, tool_use
594
406
 
595
- # -*- Yield new response using results of tool calls
596
- yield from self.response_stream(messages=messages, tool_results=tool_results)
597
- logger.debug("---------- Cohere Response End ----------")
407
+ def _get_metrics(self, response_usage) -> Metrics:
408
+ """
409
+ Parse the given Cohere usage into an Agno Metrics object.
598
410
 
599
- async def ainvoke(self, *args, **kwargs) -> Any:
600
- raise NotImplementedError(f"Async not supported on {self.name}.")
411
+ Args:
412
+ response_usage: Usage data from Cohere
601
413
 
602
- async def ainvoke_stream(self, *args, **kwargs) -> Any:
603
- raise NotImplementedError(f"Async not supported on {self.name}.")
414
+ Returns:
415
+ Metrics: Parsed metrics data
416
+ """
417
+ metrics = Metrics()
604
418
 
605
- async def aresponse(self, messages: List[Message]) -> ModelResponse:
606
- raise NotImplementedError(f"Async not supported on {self.name}.")
419
+ metrics.input_tokens = response_usage.tokens.input_tokens or 0
420
+ metrics.output_tokens = response_usage.tokens.output_tokens or 0
421
+ metrics.total_tokens = metrics.input_tokens + metrics.output_tokens
607
422
 
608
- async def aresponse_stream(self, messages: List[Message]) -> ModelResponse:
609
- raise NotImplementedError(f"Async not supported on {self.name}.")
423
+ return metrics