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
@@ -0,0 +1,373 @@
1
+ import json
2
+ from dataclasses import dataclass, field
3
+ from typing import Any, Dict, List, Optional, Tuple, Union
4
+
5
+ from agno.media import File, Image
6
+ from agno.models.message import Message
7
+ from agno.utils.log import log_error, log_warning
8
+
9
+ try:
10
+ from anthropic.types import (
11
+ TextBlock,
12
+ ToolUseBlock,
13
+ )
14
+ except ImportError:
15
+ raise ImportError("`anthropic` not installed. Please install using `pip install anthropic`")
16
+
17
+
18
+ @dataclass
19
+ class MCPToolConfiguration:
20
+ enabled: bool = True
21
+ allowed_tools: List[str] = field(default_factory=list)
22
+
23
+
24
+ @dataclass
25
+ class MCPServerConfiguration:
26
+ type: str
27
+ url: str
28
+ name: str
29
+ tool_configuration: Optional[MCPToolConfiguration] = None
30
+ authorization_token: Optional[str] = None
31
+
32
+
33
+ ROLE_MAP = {
34
+ "system": "system",
35
+ "developer": "system",
36
+ "user": "user",
37
+ "assistant": "assistant",
38
+ "tool": "user",
39
+ }
40
+
41
+
42
+ def _format_image_for_message(image: Image) -> Optional[Dict[str, Any]]:
43
+ """
44
+ Add an image to a message by converting it to base64 encoded format.
45
+ """
46
+ using_filetype = False
47
+
48
+ import base64
49
+
50
+ # 'imghdr' was deprecated in Python 3.11: https://docs.python.org/3/library/imghdr.html
51
+ # 'filetype' used as a fallback
52
+ try:
53
+ import imghdr
54
+ except ImportError:
55
+ try:
56
+ import filetype
57
+
58
+ using_filetype = True
59
+ except ImportError:
60
+ raise ImportError("`filetype` not installed. Please install using `pip install filetype`")
61
+
62
+ type_mapping = {
63
+ "jpeg": "image/jpeg",
64
+ "jpg": "image/jpeg",
65
+ "png": "image/png",
66
+ "gif": "image/gif",
67
+ "webp": "image/webp",
68
+ }
69
+
70
+ try:
71
+ img_type = None
72
+
73
+ # Case 0: Image is an Anthropic uploaded file
74
+ if image.content is not None and hasattr(image.content, "id"):
75
+ content_bytes = image.content
76
+
77
+ # Case 1: Image is a URL
78
+ if image.url is not None:
79
+ content_bytes = image.get_content_bytes() # type: ignore
80
+
81
+ # If image URL has a suffix, use it as the type (without dot)
82
+ import os
83
+ from urllib.parse import urlparse
84
+
85
+ if image.url:
86
+ parsed_url = urlparse(image.url)
87
+ _, ext = os.path.splitext(parsed_url.path)
88
+ if ext:
89
+ img_type = ext.lstrip(".").lower()
90
+
91
+ # Case 2: Image is a local file path
92
+ elif image.filepath is not None:
93
+ from pathlib import Path
94
+
95
+ path = Path(image.filepath) if isinstance(image.filepath, str) else image.filepath
96
+ if path.exists() and path.is_file():
97
+ with open(image.filepath, "rb") as f:
98
+ content_bytes = f.read()
99
+
100
+ # If image file path has a suffix, use it as the type (without dot)
101
+ path_ext = path.suffix.lstrip(".")
102
+ if path_ext:
103
+ img_type = path_ext.lower()
104
+ else:
105
+ log_error(f"Image file not found: {image}")
106
+ return None
107
+
108
+ # Case 3: Image is a bytes object
109
+ elif image.content is not None:
110
+ content_bytes = image.content
111
+
112
+ else:
113
+ log_error(f"Unsupported image type: {type(image)}")
114
+ return None
115
+
116
+ if not img_type:
117
+ if using_filetype:
118
+ kind = filetype.guess(content_bytes)
119
+ if not kind:
120
+ log_error("Unable to determine image type")
121
+ return None
122
+
123
+ img_type = kind.extension
124
+ else:
125
+ img_type = imghdr.what(None, h=content_bytes) # type: ignore
126
+
127
+ if not img_type:
128
+ log_error("Unable to determine image type")
129
+ return None
130
+
131
+ media_type = type_mapping.get(img_type)
132
+ if not media_type:
133
+ log_error(f"Unsupported image type: {img_type}")
134
+ return None
135
+
136
+ return {
137
+ "type": "image",
138
+ "source": {
139
+ "type": "base64",
140
+ "media_type": media_type,
141
+ "data": base64.b64encode(content_bytes).decode("utf-8"), # type: ignore
142
+ },
143
+ }
144
+
145
+ except Exception as e:
146
+ log_error(f"Error processing image: {e}")
147
+ return None
148
+
149
+
150
+ def _format_file_for_message(file: File) -> Optional[Dict[str, Any]]:
151
+ """
152
+ Add a document url or base64 encoded content to a message.
153
+ """
154
+
155
+ mime_mapping = {
156
+ "application/pdf": "base64",
157
+ "text/plain": "text",
158
+ }
159
+
160
+ # Case 0: File is an Anthropic uploaded file
161
+ if file.external is not None and hasattr(file.external, "id"):
162
+ return {
163
+ "type": "document",
164
+ "source": {
165
+ "type": "file",
166
+ "file_id": file.external.id,
167
+ },
168
+ }
169
+
170
+ # Case 1: Document is a URL
171
+ if file.url is not None:
172
+ return {
173
+ "type": "document",
174
+ "source": {
175
+ "type": "url",
176
+ "url": file.url,
177
+ },
178
+ "citations": {"enabled": True},
179
+ }
180
+ # Case 2: Document is a local file path
181
+ elif file.filepath is not None:
182
+ import base64
183
+ from pathlib import Path
184
+
185
+ path = Path(file.filepath) if isinstance(file.filepath, str) else file.filepath
186
+ if path.exists() and path.is_file():
187
+ file_data = base64.standard_b64encode(path.read_bytes()).decode("utf-8")
188
+
189
+ # Determine media type
190
+ media_type = file.mime_type
191
+ if media_type is None:
192
+ import mimetypes
193
+
194
+ media_type = mimetypes.guess_type(file.filepath)[0] or "application/pdf"
195
+
196
+ # Map media type to type, default to "base64" if no mapping exists
197
+ type = mime_mapping.get(media_type, "base64")
198
+
199
+ return {
200
+ "type": "document",
201
+ "source": {
202
+ "type": type,
203
+ "media_type": media_type,
204
+ "data": file_data,
205
+ },
206
+ "citations": {"enabled": True},
207
+ }
208
+ else:
209
+ log_error(f"Document file not found: {file}")
210
+ return None
211
+ # Case 3: Document is bytes content
212
+ elif file.content is not None:
213
+ import base64
214
+
215
+ file_data = base64.standard_b64encode(file.content).decode("utf-8")
216
+ return {
217
+ "type": "document",
218
+ "source": {"type": "base64", "media_type": file.mime_type or "application/pdf", "data": file_data},
219
+ "citations": {"enabled": True},
220
+ }
221
+ return None
222
+
223
+
224
+ def format_messages(
225
+ messages: List[Message], compress_tool_results: bool = False
226
+ ) -> Tuple[List[Dict[str, Union[str, list]]], str]:
227
+ """
228
+ Process the list of messages and separate them into API messages and system messages.
229
+
230
+ Args:
231
+ messages (List[Message]): The list of messages to process.
232
+ compress_tool_results: Whether to compress tool results.
233
+
234
+ Returns:
235
+ Tuple[List[Dict[str, Union[str, list]]], str]: A tuple containing the list of API messages and the concatenated system messages.
236
+ """
237
+ chat_messages: List[Dict[str, Union[str, list]]] = []
238
+ system_messages: List[str] = []
239
+
240
+ for message in messages:
241
+ content = message.content or ""
242
+ # Both "system" and "developer" roles should be extracted as system messages
243
+ if message.role in ("system", "developer"):
244
+ if content is not None:
245
+ system_messages.append(content) # type: ignore
246
+ continue
247
+ elif message.role == "user":
248
+ if isinstance(content, str):
249
+ content = [{"type": "text", "text": content}]
250
+
251
+ if message.images is not None:
252
+ for image in message.images:
253
+ image_content = _format_image_for_message(image)
254
+ if image_content:
255
+ content.append(image_content)
256
+
257
+ if message.files is not None:
258
+ for file in message.files:
259
+ file_content = _format_file_for_message(file)
260
+ if file_content:
261
+ content.append(file_content)
262
+
263
+ if message.audio is not None and len(message.audio) > 0:
264
+ log_warning("Audio input is currently unsupported.")
265
+
266
+ if message.videos is not None and len(message.videos) > 0:
267
+ log_warning("Video input is currently unsupported.")
268
+
269
+ elif message.role == "assistant":
270
+ content = []
271
+
272
+ if message.reasoning_content is not None and message.provider_data is not None:
273
+ from anthropic.types import RedactedThinkingBlock, ThinkingBlock
274
+
275
+ content.append(
276
+ ThinkingBlock(
277
+ thinking=message.reasoning_content,
278
+ signature=message.provider_data.get("signature"),
279
+ type="thinking",
280
+ )
281
+ )
282
+
283
+ if message.redacted_reasoning_content is not None:
284
+ from anthropic.types import RedactedThinkingBlock
285
+
286
+ content.append(
287
+ RedactedThinkingBlock(data=message.redacted_reasoning_content, type="redacted_reasoning_content")
288
+ )
289
+
290
+ if isinstance(message.content, str) and message.content and len(message.content.strip()) > 0:
291
+ content.append(TextBlock(text=message.content, type="text"))
292
+
293
+ if message.tool_calls:
294
+ for tool_call in message.tool_calls:
295
+ content.append(
296
+ ToolUseBlock(
297
+ id=tool_call["id"],
298
+ input=json.loads(tool_call["function"]["arguments"])
299
+ if "arguments" in tool_call["function"]
300
+ else {},
301
+ name=tool_call["function"]["name"],
302
+ type="tool_use",
303
+ )
304
+ )
305
+ elif message.role == "tool":
306
+ content = []
307
+
308
+ # Use compressed content for tool messages if compression is active
309
+ tool_result = message.get_content(use_compressed_content=compress_tool_results)
310
+
311
+ content.append(
312
+ {
313
+ "type": "tool_result",
314
+ "tool_use_id": message.tool_call_id,
315
+ "content": str(tool_result),
316
+ }
317
+ )
318
+
319
+ # Skip empty assistant responses
320
+ if message.role == "assistant" and not content:
321
+ continue
322
+
323
+ chat_messages.append({"role": ROLE_MAP[message.role], "content": content}) # type: ignore
324
+ return chat_messages, " ".join(system_messages)
325
+
326
+
327
+ def format_tools_for_model(tools: Optional[List[Dict[str, Any]]] = None) -> Optional[List[Dict[str, Any]]]:
328
+ """
329
+ Transforms function definitions into a format accepted by the Anthropic API.
330
+ Now supports strict mode for structured outputs.
331
+ """
332
+ if not tools:
333
+ return None
334
+
335
+ parsed_tools: List[Dict[str, Any]] = []
336
+ for tool_def in tools:
337
+ if tool_def.get("type", "") != "function":
338
+ parsed_tools.append(tool_def)
339
+ continue
340
+
341
+ func_def = tool_def.get("function", {})
342
+ parameters: Dict[str, Any] = func_def.get("parameters", {})
343
+ properties: Dict[str, Any] = parameters.get("properties", {})
344
+ required: List[str] = parameters.get("required", [])
345
+ required_params: List[str] = required
346
+
347
+ input_properties: Dict[str, Any] = {}
348
+ for param_name, param_info in properties.items():
349
+ # Preserve the complete schema structure for complex types
350
+ input_properties[param_name] = param_info.copy()
351
+
352
+ # Ensure description is present (default to empty if missing)
353
+ if "description" not in input_properties[param_name]:
354
+ input_properties[param_name]["description"] = ""
355
+
356
+ tool = {
357
+ "name": func_def.get("name") or "",
358
+ "description": func_def.get("description") or "",
359
+ "input_schema": {
360
+ "type": parameters.get("type", "object"),
361
+ "properties": input_properties,
362
+ "required": required_params,
363
+ "additionalProperties": False,
364
+ },
365
+ }
366
+
367
+ # Add strict mode if specified (check both function dict and tool_def top level)
368
+ strict_mode = func_def.get("strict") or tool_def.get("strict")
369
+ if strict_mode is True:
370
+ tool["strict"] = True
371
+
372
+ parsed_tools.append(tool)
373
+ return parsed_tools
@@ -0,0 +1,94 @@
1
+ from pathlib import Path
2
+ from typing import Any, Dict, List, Sequence
3
+
4
+ from agno.media import Image
5
+ from agno.models.message import Message
6
+ from agno.utils.log import log_error, log_warning
7
+
8
+
9
+ def _format_images_for_message(message: Message, images: Sequence[Image]) -> List[Dict[str, Any]]:
10
+ """
11
+ Format an image into the format expected by WatsonX.
12
+ """
13
+
14
+ # Create a default message content with text
15
+ message_content_with_image: List[Dict[str, Any]] = [{"type": "text", "text": message.content}]
16
+
17
+ # Add images to the message content
18
+ for image in images:
19
+ try:
20
+ if image.content is not None:
21
+ image_content = image.content
22
+ elif image.url is not None:
23
+ image_content = image.get_content_bytes() # type: ignore
24
+ elif image.filepath is not None:
25
+ if isinstance(image.filepath, Path):
26
+ image_content = image.filepath.read_bytes()
27
+ else:
28
+ with open(image.filepath, "rb") as f:
29
+ image_content = f.read()
30
+ else:
31
+ log_warning(f"Unsupported image format: {image}")
32
+ continue
33
+
34
+ if image_content is not None:
35
+ import base64
36
+
37
+ base64_image = base64.b64encode(image_content).decode("utf-8")
38
+ image_url = f"data:image/jpeg;base64,{base64_image}"
39
+ image_payload = {"type": "image_url", "image_url": {"url": image_url}}
40
+ message_content_with_image.append(image_payload)
41
+
42
+ except Exception as e:
43
+ log_error(f"Failed to process image: {str(e)}")
44
+
45
+ # Update the message content with the images
46
+ return message_content_with_image
47
+
48
+
49
+ def format_messages(messages: List[Message], compress_tool_results: bool = False) -> List[Dict[str, Any]]:
50
+ """
51
+ Format messages for the Cohere API.
52
+
53
+ Args:
54
+ messages (List[Message]): The list of messages.
55
+ compress_tool_results: Whether to compress tool results.
56
+
57
+ Returns:
58
+ List[Dict[str, Any]]: The formatted messages.
59
+ """
60
+ formatted_messages = []
61
+ for message in messages:
62
+ # Use compressed content for tool messages if compression is active
63
+ content = message.content
64
+
65
+ if message.role == "tool":
66
+ content = message.get_content(use_compressed_content=compress_tool_results)
67
+
68
+ message_dict = {
69
+ "role": message.role,
70
+ "content": content,
71
+ "name": message.name,
72
+ "tool_call_id": message.tool_call_id,
73
+ "tool_calls": message.tool_calls,
74
+ }
75
+
76
+ if message.images is not None and len(message.images) > 0:
77
+ # Ignore non-string message content
78
+ if isinstance(message.content, str):
79
+ message_content_with_image = _format_images_for_message(message=message, images=message.images)
80
+ if len(message_content_with_image) > 1:
81
+ message_dict["content"] = message_content_with_image
82
+
83
+ if message.videos is not None and len(message.videos) > 0:
84
+ log_warning("Video input is currently unsupported.")
85
+
86
+ if message.audio is not None and len(message.audio) > 0:
87
+ log_warning("Audio input is currently unsupported.")
88
+
89
+ if message.files is not None and len(message.files) > 0:
90
+ log_warning("File input is currently unsupported.")
91
+
92
+ message_dict = {k: v for k, v in message_dict.items() if v is not None}
93
+ formatted_messages.append(message_dict)
94
+ return formatted_messages
@@ -0,0 +1,85 @@
1
+ from typing import Any, Dict
2
+
3
+ from agno.agent import Message
4
+ from agno.utils.log import log_warning
5
+ from agno.utils.openai import process_image
6
+
7
+ ROLE_MAP = {
8
+ "user": "user",
9
+ "assistant": "assistant",
10
+ "system": "system",
11
+ "tool": "tool",
12
+ }
13
+
14
+ TOOL_CALL_ROLE_MAP = {
15
+ "user": "user",
16
+ "assistant": "assistant",
17
+ "system": "user",
18
+ "tool": "tool",
19
+ }
20
+
21
+
22
+ def format_message(
23
+ message: Message, openai_like: bool = False, tool_calls: bool = False, compress_tool_results: bool = False
24
+ ) -> Dict[str, Any]:
25
+ """
26
+ Format a message into the format expected by Llama API.
27
+
28
+ Args:
29
+ message (Message): The message to format.
30
+ openai_like (bool): Whether to format the message as an OpenAI-like message.
31
+ tool_calls (bool): Whether tool calls are present.
32
+ compress_tool_results: Whether to compress tool results.
33
+
34
+ Returns:
35
+ Dict[str, Any]: The formatted message.
36
+ """
37
+ message_dict: Dict[str, Any] = {
38
+ "role": ROLE_MAP[message.role] if not tool_calls else TOOL_CALL_ROLE_MAP[message.role],
39
+ "content": [{"type": "text", "text": message.content or " "}],
40
+ "name": message.name,
41
+ "tool_call_id": message.tool_call_id,
42
+ "tool_calls": message.tool_calls,
43
+ }
44
+ message_dict = {k: v for k, v in message_dict.items() if v is not None}
45
+
46
+ if message.images is not None and len(message.images) > 0:
47
+ for image in message.images:
48
+ image_payload = process_image(image)
49
+ if image_payload:
50
+ message_dict["content"].append(image_payload)
51
+
52
+ if message.videos is not None and len(message.videos) > 0:
53
+ log_warning("Video input is currently unsupported.")
54
+
55
+ if message.audio is not None and len(message.audio) > 0:
56
+ log_warning("Audio input is currently unsupported.")
57
+
58
+ if message.role == "tool":
59
+ # Use compressed content if compression is active
60
+ content = message.get_content(use_compressed_content=compress_tool_results)
61
+
62
+ message_dict = {
63
+ "role": "tool",
64
+ "tool_call_id": message.tool_call_id,
65
+ "content": content,
66
+ }
67
+
68
+ if message.role == "assistant":
69
+ text_content = {"type": "text", "text": message.content or " "}
70
+
71
+ if message.tool_calls is not None and len(message.tool_calls) > 0:
72
+ message_dict = {
73
+ "content": [text_content] if openai_like else text_content,
74
+ "role": "assistant",
75
+ "tool_calls": message.tool_calls,
76
+ "stop_reason": "tool_calls",
77
+ }
78
+ else:
79
+ message_dict = {
80
+ "role": "assistant",
81
+ "content": [text_content] if openai_like else text_content,
82
+ "stop_reason": "stop",
83
+ }
84
+
85
+ return message_dict
@@ -0,0 +1,100 @@
1
+ from typing import Any, List, Optional, Union
2
+
3
+ from agno.media import Image
4
+ from agno.models.message import Message
5
+ from agno.utils.log import log_error, log_warning
6
+
7
+ try:
8
+ # TODO: Adapt these imports to the new Mistral SDK versions
9
+ from mistralai.models import ( # type: ignore
10
+ AssistantMessage, # type: ignore
11
+ ImageURLChunk, # type: ignore
12
+ SystemMessage, # type: ignore
13
+ TextChunk, # type: ignore
14
+ ToolMessage, # type: ignore
15
+ UserMessage, # type: ignore
16
+ )
17
+
18
+ MistralMessage = Union[UserMessage, AssistantMessage, SystemMessage, ToolMessage]
19
+
20
+ except ImportError:
21
+ raise ImportError("`mistralai` not installed. Please install using `pip install mistralai`")
22
+
23
+
24
+ def _format_image_for_message(image: Image) -> Optional[ImageURLChunk]:
25
+ # Case 1: Image is a URL
26
+ if image.url is not None:
27
+ return ImageURLChunk(image_url=image.url)
28
+ # Case 2: Image is a local file path
29
+ elif image.filepath is not None:
30
+ import base64
31
+ from pathlib import Path
32
+
33
+ path = Path(image.filepath) if isinstance(image.filepath, str) else image.filepath
34
+ if not path.exists() or not path.is_file():
35
+ log_error(f"Image file not found: {image}")
36
+ raise FileNotFoundError(f"Image file not found: {image}")
37
+
38
+ with open(image.filepath, "rb") as image_file:
39
+ base64_image = base64.b64encode(image_file.read()).decode("utf-8")
40
+ return ImageURLChunk(image_url=f"data:image/jpeg;base64,{base64_image}")
41
+
42
+ # Case 3: Image is a bytes object
43
+ elif image.content is not None:
44
+ import base64
45
+
46
+ base64_image = base64.b64encode(image.content).decode("utf-8")
47
+ return ImageURLChunk(image_url=f"data:image/jpeg;base64,{base64_image}")
48
+ return None
49
+
50
+
51
+ def format_messages(messages: List[Message], compress_tool_results: bool = False) -> List[MistralMessage]:
52
+ mistral_messages: List[MistralMessage] = []
53
+
54
+ for message in messages:
55
+ mistral_message: MistralMessage
56
+ if message.role == "user":
57
+ if message.audio is not None and len(message.audio) > 0:
58
+ log_warning("Audio input is currently unsupported.")
59
+
60
+ if message.files is not None and len(message.files) > 0:
61
+ log_warning("File input is currently unsupported.")
62
+
63
+ if message.videos is not None and len(message.videos) > 0:
64
+ log_warning("Video input is currently unsupported.")
65
+
66
+ if message.images is not None:
67
+ content: List[Any] = [TextChunk(type="text", text=message.content)]
68
+ for image in message.images:
69
+ image_content = _format_image_for_message(image)
70
+ if image_content:
71
+ content.append(image_content)
72
+ mistral_message = UserMessage(role="user", content=content)
73
+ else:
74
+ mistral_message = UserMessage(role="user", content=message.content)
75
+ elif message.role == "assistant":
76
+ if message.reasoning_content is not None:
77
+ mistral_message = UserMessage(role="user", content=message.content)
78
+ elif message.tool_calls is not None:
79
+ mistral_message = AssistantMessage(
80
+ role="assistant", content=message.content, tool_calls=message.tool_calls
81
+ )
82
+ else:
83
+ mistral_message = AssistantMessage(role=message.role, content=message.content)
84
+ elif message.role == "system":
85
+ mistral_message = SystemMessage(role="system", content=message.content)
86
+ elif message.role == "tool":
87
+ # Get compressed content if compression is active
88
+ tool_content = message.get_content(use_compressed_content=compress_tool_results)
89
+ mistral_message = ToolMessage(name="tool", content=tool_content, tool_call_id=message.tool_call_id)
90
+ else:
91
+ raise ValueError(f"Unknown role: {message.role}")
92
+
93
+ mistral_messages.append(mistral_message)
94
+
95
+ # Check if the last message is an assistant message
96
+ if mistral_messages and hasattr(mistral_messages[-1], "role") and mistral_messages[-1].role == "assistant":
97
+ # Set prefix=True for the last assistant message to allow it as the last message
98
+ mistral_messages[-1].prefix = True
99
+
100
+ return mistral_messages