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
agno/eval/reliability.py CHANGED
@@ -1,14 +1,18 @@
1
- from dataclasses import asdict, dataclass
1
+ from dataclasses import asdict, dataclass, field
2
2
  from os import getenv
3
- from pathlib import Path
4
- from typing import TYPE_CHECKING, List, Optional
3
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
5
4
  from uuid import uuid4
6
5
 
6
+ from agno.db.base import AsyncBaseDb, BaseDb
7
+ from agno.run.team import TeamRunOutput
8
+
7
9
  if TYPE_CHECKING:
8
10
  from rich.console import Console
9
11
 
10
- from agno.run.response import RunResponse
11
- from agno.utils.log import logger, set_log_level_to_debug, set_log_level_to_info
12
+ from agno.agent import RunOutput
13
+ from agno.db.schemas.evals import EvalType
14
+ from agno.eval.utils import async_log_eval, log_eval_run, store_result_in_file
15
+ from agno.utils.log import logger
12
16
 
13
17
 
14
18
  @dataclass
@@ -40,52 +44,50 @@ class ReliabilityEval:
40
44
 
41
45
  # Evaluation name
42
46
  name: Optional[str] = None
43
-
44
- # Evaluation UUID (autogenerated if not set)
45
- eval_id: Optional[str] = None
47
+ # Evaluation UUID
48
+ eval_id: str = field(default_factory=lambda: str(uuid4()))
46
49
 
47
50
  # Agent response
48
- agent_response: Optional[RunResponse] = None
49
-
51
+ agent_response: Optional[RunOutput] = None
52
+ # Team response
53
+ team_response: Optional[TeamRunOutput] = None
50
54
  # Expected tool calls
51
55
  expected_tool_calls: Optional[List[str]] = None
52
-
53
56
  # Result of the evaluation
54
57
  result: Optional[ReliabilityResult] = None
55
58
 
56
- # Print summary of results
57
- print_summary: bool = False
58
59
  # Print detailed results
59
60
  print_results: bool = False
60
- # Save the result to a file
61
- save_result_to_file: Optional[str] = None
62
-
63
- # debug_mode=True enables debug logs
64
- debug_mode: bool = False
65
-
66
- def set_eval_id(self) -> str:
67
- if self.eval_id is None:
68
- self.eval_id = str(uuid4())
69
- logger.debug(f"*********** Evaluation ID: {self.eval_id} ***********")
70
- return self.eval_id
71
-
72
- def set_debug_mode(self) -> None:
73
- if self.debug_mode or getenv("AGNO_DEBUG", "false").lower() == "true":
74
- self.debug_mode = True
75
- set_log_level_to_debug()
76
- logger.debug("Debug logs enabled")
77
- else:
78
- set_log_level_to_info()
79
-
80
- def run(self, *, print_summary: bool = False, print_results: bool = False) -> Optional[ReliabilityResult]:
61
+ # If set, results will be saved in the given file path
62
+ file_path_to_save_results: Optional[str] = None
63
+ # Enable debug logs
64
+ debug_mode: bool = getenv("AGNO_DEBUG", "false").lower() == "true"
65
+ # The database to store Evaluation results
66
+ db: Optional[Union[BaseDb, AsyncBaseDb]] = None
67
+
68
+ # Telemetry settings
69
+ # telemetry=True logs minimal telemetry for analytics
70
+ # This helps us improve our Evals and provide better support
71
+ telemetry: bool = True
72
+
73
+ def run(self, *, print_results: bool = False) -> Optional[ReliabilityResult]:
74
+ if isinstance(self.db, AsyncBaseDb):
75
+ raise ValueError("run() is not supported with an async DB. Please use arun() instead.")
76
+
77
+ if self.agent_response is None and self.team_response is None:
78
+ raise ValueError("You need to provide 'agent_response' or 'team_response' to run the evaluation.")
79
+
80
+ if self.agent_response is not None and self.team_response is not None:
81
+ raise ValueError(
82
+ "You need to provide only one of 'agent_response' or 'team_response' to run the evaluation."
83
+ )
84
+
81
85
  from rich.console import Console
82
86
  from rich.live import Live
83
87
  from rich.status import Status
84
88
 
85
- self.set_eval_id()
86
- self.set_debug_mode()
87
- self.print_results = print_results
88
- self.print_summary = print_summary
89
+ # Generate unique run_id for this execution (don't modify self.eval_id due to concurrency)
90
+ run_id = str(uuid4())
89
91
 
90
92
  # Add a spinner while running the evaluations
91
93
  console = Console()
@@ -95,20 +97,34 @@ class ReliabilityEval:
95
97
 
96
98
  actual_tool_calls = None
97
99
  if self.agent_response is not None:
98
- for message in reversed(self.agent_response.messages): # type: ignore
99
- if message.tool_calls:
100
- if actual_tool_calls is None:
101
- actual_tool_calls = message.tool_calls
102
- else:
103
- actual_tool_calls.append(message.tool_calls[0]) # type: ignore
100
+ messages = self.agent_response.messages
101
+ elif self.team_response is not None:
102
+ messages = self.team_response.messages or []
103
+ for member_response in self.team_response.member_responses:
104
+ if member_response.messages is not None:
105
+ messages += member_response.messages
106
+
107
+ for message in reversed(messages): # type: ignore
108
+ if message.tool_calls:
109
+ if actual_tool_calls is None:
110
+ actual_tool_calls = message.tool_calls
111
+ else:
112
+ actual_tool_calls.append(message.tool_calls[0]) # type: ignore
104
113
 
105
114
  failed_tool_calls = []
106
115
  passed_tool_calls = []
107
- for tool_call in actual_tool_calls: # type: ignore
108
- if tool_call.get("function", {}).get("name") not in self.expected_tool_calls: # type: ignore
109
- failed_tool_calls.append(tool_call.get("function", {}).get("name"))
110
- else:
111
- passed_tool_calls.append(tool_call.get("function", {}).get("name"))
116
+ if not actual_tool_calls:
117
+ failed_tool_calls = self.expected_tool_calls or []
118
+ else:
119
+ for tool_call in actual_tool_calls: # type: ignore
120
+ tool_name = tool_call.get("function", {}).get("name")
121
+ if not tool_name:
122
+ continue
123
+ else:
124
+ if self.expected_tool_calls is not None and tool_name not in self.expected_tool_calls:
125
+ failed_tool_calls.append(tool_call.get("function", {}).get("name"))
126
+ else:
127
+ passed_tool_calls.append(tool_call.get("function", {}).get("name"))
112
128
 
113
129
  self.result = ReliabilityResult(
114
130
  eval_status="PASSED" if len(failed_tool_calls) == 0 else "FAILED",
@@ -116,21 +132,184 @@ class ReliabilityEval:
116
132
  passed_tool_calls=passed_tool_calls,
117
133
  )
118
134
 
119
- # -*- Save result to file if save_result_to_file is set
120
- if self.save_result_to_file is not None and self.result is not None:
121
- try:
122
- import json
135
+ # Save result to file if requested
136
+ if self.file_path_to_save_results is not None and self.result is not None:
137
+ store_result_in_file(
138
+ file_path=self.file_path_to_save_results,
139
+ name=self.name,
140
+ eval_id=self.eval_id,
141
+ result=self.result,
142
+ )
143
+
144
+ # Print results if requested
145
+ if self.print_results or print_results:
146
+ self.result.print_eval(console)
147
+
148
+ # Log results to the Agno platform if requested
149
+ if self.db:
150
+ if self.agent_response is not None:
151
+ agent_id = self.agent_response.agent_id
152
+ team_id = None
153
+ model_id = self.agent_response.model
154
+ model_provider = self.agent_response.model_provider
155
+ elif self.team_response is not None:
156
+ agent_id = None
157
+ team_id = self.team_response.team_id
158
+ model_id = self.team_response.model
159
+ model_provider = self.team_response.model_provider
160
+
161
+ eval_input = {
162
+ "expected_tool_calls": self.expected_tool_calls,
163
+ }
164
+
165
+ log_eval_run(
166
+ db=self.db,
167
+ run_id=self.eval_id, # type: ignore
168
+ run_data=asdict(self.result),
169
+ eval_type=EvalType.RELIABILITY,
170
+ name=self.name if self.name is not None else None,
171
+ agent_id=agent_id,
172
+ team_id=team_id,
173
+ model_id=model_id,
174
+ model_provider=model_provider,
175
+ eval_input=eval_input,
176
+ )
177
+
178
+ if self.telemetry:
179
+ from agno.api.evals import EvalRunCreate, create_eval_run_telemetry
180
+
181
+ create_eval_run_telemetry(
182
+ eval_run=EvalRunCreate(
183
+ run_id=self.eval_id,
184
+ eval_type=EvalType.RELIABILITY,
185
+ data=self._get_telemetry_data(),
186
+ ),
187
+ )
188
+
189
+ logger.debug(f"*********** Evaluation End: {run_id} ***********")
190
+ return self.result
191
+
192
+ async def arun(self, *, print_results: bool = False) -> Optional[ReliabilityResult]:
193
+ if self.agent_response is None and self.team_response is None:
194
+ raise ValueError("You need to provide 'agent_response' or 'team_response' to run the evaluation.")
195
+
196
+ if self.agent_response is not None and self.team_response is not None:
197
+ raise ValueError(
198
+ "You need to provide only one of 'agent_response' or 'team_response' to run the evaluation."
199
+ )
200
+
201
+ from rich.console import Console
202
+ from rich.live import Live
203
+ from rich.status import Status
204
+
205
+ # Generate unique run_id for this execution (don't modify self.eval_id due to concurrency)
206
+ run_id = str(uuid4())
207
+
208
+ # Add a spinner while running the evaluations
209
+ console = Console()
210
+ with Live(console=console, transient=True) as live_log:
211
+ status = Status("Running evaluation...", spinner="dots", speed=1.0, refresh_per_second=10)
212
+ live_log.update(status)
213
+
214
+ actual_tool_calls = None
215
+ if self.agent_response is not None:
216
+ messages = self.agent_response.messages
217
+ elif self.team_response is not None:
218
+ messages = self.team_response.messages or []
219
+ for member_response in self.team_response.member_responses:
220
+ if member_response.messages is not None:
221
+ messages += member_response.messages
222
+
223
+ for message in reversed(messages): # type: ignore
224
+ if message.tool_calls:
225
+ if actual_tool_calls is None:
226
+ actual_tool_calls = message.tool_calls
227
+ else:
228
+ actual_tool_calls.append(message.tool_calls[0]) # type: ignore
229
+
230
+ failed_tool_calls = []
231
+ passed_tool_calls = []
232
+ if not actual_tool_calls:
233
+ failed_tool_calls = self.expected_tool_calls or []
234
+ else:
235
+ for tool_call in actual_tool_calls: # type: ignore
236
+ tool_name = tool_call.get("function", {}).get("name")
237
+ if not tool_name:
238
+ continue
239
+ else:
240
+ if self.expected_tool_calls is not None and tool_name not in self.expected_tool_calls:
241
+ failed_tool_calls.append(tool_call.get("function", {}).get("name"))
242
+ else:
243
+ passed_tool_calls.append(tool_call.get("function", {}).get("name"))
244
+
245
+ self.result = ReliabilityResult(
246
+ eval_status="PASSED" if len(failed_tool_calls) == 0 else "FAILED",
247
+ failed_tool_calls=failed_tool_calls,
248
+ passed_tool_calls=passed_tool_calls,
249
+ )
123
250
 
124
- fn_path = Path(self.save_result_to_file.format(name=self.name, eval_id=self.eval_id))
125
- if not fn_path.parent.exists():
126
- fn_path.parent.mkdir(parents=True, exist_ok=True)
127
- fn_path.write_text(json.dumps(asdict(self.result), indent=4))
128
- except Exception as e:
129
- logger.warning(f"Failed to save result to file: {e}")
251
+ # Save result to file if requested
252
+ if self.file_path_to_save_results is not None and self.result is not None:
253
+ store_result_in_file(
254
+ file_path=self.file_path_to_save_results,
255
+ name=self.name,
256
+ eval_id=run_id,
257
+ result=self.result,
258
+ )
130
259
 
131
- # Show results
132
- if self.print_summary or self.print_results:
260
+ # Print results if requested
261
+ if self.print_results or print_results:
133
262
  self.result.print_eval(console)
134
263
 
135
- logger.debug(f"*********** Evaluation End: {self.eval_id} ***********")
264
+ # Log results to the Agno platform if requested
265
+ if self.db:
266
+ if self.agent_response is not None:
267
+ agent_id = self.agent_response.agent_id
268
+ team_id = None
269
+ model_id = self.agent_response.model
270
+ model_provider = self.agent_response.model_provider
271
+ elif self.team_response is not None:
272
+ agent_id = None
273
+ team_id = self.team_response.team_id
274
+ model_id = self.team_response.model
275
+ model_provider = self.team_response.model_provider
276
+
277
+ eval_input = {
278
+ "expected_tool_calls": self.expected_tool_calls,
279
+ }
280
+
281
+ await async_log_eval(
282
+ db=self.db,
283
+ run_id=self.eval_id, # type: ignore
284
+ run_data=asdict(self.result),
285
+ eval_type=EvalType.RELIABILITY,
286
+ name=self.name if self.name is not None else None,
287
+ agent_id=agent_id,
288
+ team_id=team_id,
289
+ model_id=model_id,
290
+ model_provider=model_provider,
291
+ eval_input=eval_input,
292
+ )
293
+
294
+ if self.telemetry:
295
+ from agno.api.evals import EvalRunCreate, async_create_eval_run_telemetry
296
+
297
+ await async_create_eval_run_telemetry(
298
+ eval_run=EvalRunCreate(
299
+ run_id=self.eval_id,
300
+ eval_type=EvalType.RELIABILITY,
301
+ data=self._get_telemetry_data(),
302
+ ),
303
+ )
304
+
305
+ logger.debug(f"*********** Evaluation End: {run_id} ***********")
136
306
  return self.result
307
+
308
+ def _get_telemetry_data(self) -> Dict[str, Any]:
309
+ """Get the telemetry data for the evaluation"""
310
+ return {
311
+ "team_id": self.team_response.team_id if self.team_response else None,
312
+ "agent_id": self.agent_response.agent_id if self.agent_response else None,
313
+ "model_id": self.agent_response.model if self.agent_response else None,
314
+ "model_provider": self.agent_response.model_provider if self.agent_response else None,
315
+ }
agno/eval/utils.py ADDED
@@ -0,0 +1,120 @@
1
+ from dataclasses import asdict
2
+ from pathlib import Path
3
+ from typing import TYPE_CHECKING, Optional, Union
4
+
5
+ from agno.db.base import AsyncBaseDb, BaseDb
6
+ from agno.db.schemas.evals import EvalRunRecord, EvalType
7
+ from agno.utils.log import log_debug, logger
8
+
9
+ if TYPE_CHECKING:
10
+ from agno.eval.accuracy import AccuracyResult
11
+ from agno.eval.agent_as_judge import AgentAsJudgeResult
12
+ from agno.eval.performance import PerformanceResult
13
+ from agno.eval.reliability import ReliabilityResult
14
+
15
+
16
+ def log_eval_run(
17
+ db: BaseDb,
18
+ run_id: str,
19
+ run_data: dict,
20
+ eval_type: EvalType,
21
+ eval_input: dict,
22
+ agent_id: Optional[str] = None,
23
+ model_id: Optional[str] = None,
24
+ model_provider: Optional[str] = None,
25
+ name: Optional[str] = None,
26
+ evaluated_component_name: Optional[str] = None,
27
+ team_id: Optional[str] = None,
28
+ workflow_id: Optional[str] = None,
29
+ ) -> None:
30
+ """Call the API to create an evaluation run."""
31
+
32
+ try:
33
+ db.create_eval_run(
34
+ EvalRunRecord(
35
+ run_id=run_id,
36
+ eval_type=eval_type,
37
+ eval_data=run_data,
38
+ eval_input=eval_input,
39
+ agent_id=agent_id,
40
+ model_id=model_id,
41
+ model_provider=model_provider,
42
+ name=name,
43
+ evaluated_component_name=evaluated_component_name,
44
+ team_id=team_id,
45
+ workflow_id=workflow_id,
46
+ )
47
+ )
48
+ except Exception as e:
49
+ log_debug(f"Could not create agent event: {e}")
50
+
51
+
52
+ async def async_log_eval(
53
+ db: Union[BaseDb, AsyncBaseDb],
54
+ run_id: str,
55
+ run_data: dict,
56
+ eval_type: EvalType,
57
+ eval_input: dict,
58
+ agent_id: Optional[str] = None,
59
+ model_id: Optional[str] = None,
60
+ model_provider: Optional[str] = None,
61
+ name: Optional[str] = None,
62
+ evaluated_component_name: Optional[str] = None,
63
+ team_id: Optional[str] = None,
64
+ workflow_id: Optional[str] = None,
65
+ ) -> None:
66
+ """Call the API to create an evaluation run."""
67
+
68
+ try:
69
+ if isinstance(db, AsyncBaseDb):
70
+ await db.create_eval_run(
71
+ EvalRunRecord(
72
+ run_id=run_id,
73
+ eval_type=eval_type,
74
+ eval_data=run_data,
75
+ eval_input=eval_input,
76
+ agent_id=agent_id,
77
+ model_id=model_id,
78
+ model_provider=model_provider,
79
+ name=name,
80
+ evaluated_component_name=evaluated_component_name,
81
+ team_id=team_id,
82
+ workflow_id=workflow_id,
83
+ )
84
+ )
85
+ else:
86
+ db.create_eval_run(
87
+ EvalRunRecord(
88
+ run_id=run_id,
89
+ eval_type=eval_type,
90
+ eval_data=run_data,
91
+ eval_input=eval_input,
92
+ agent_id=agent_id,
93
+ model_id=model_id,
94
+ model_provider=model_provider,
95
+ name=name,
96
+ evaluated_component_name=evaluated_component_name,
97
+ team_id=team_id,
98
+ workflow_id=workflow_id,
99
+ )
100
+ )
101
+ except Exception as e:
102
+ log_debug(f"Could not create agent event: {e}")
103
+
104
+
105
+ def store_result_in_file(
106
+ file_path: str,
107
+ result: Union["AccuracyResult", "AgentAsJudgeResult", "PerformanceResult", "ReliabilityResult"],
108
+ eval_id: Optional[str] = None,
109
+ name: Optional[str] = None,
110
+ ):
111
+ """Store the given result in the given file path"""
112
+ try:
113
+ import json
114
+
115
+ fn_path = Path(file_path.format(name=name, eval_id=eval_id))
116
+ if not fn_path.parent.exists():
117
+ fn_path.parent.mkdir(parents=True, exist_ok=True)
118
+ fn_path.write_text(json.dumps(asdict(result), indent=4))
119
+ except Exception as e:
120
+ logger.warning(f"Failed to save result to file: {e}")
agno/exceptions.py CHANGED
@@ -1,4 +1,6 @@
1
- from typing import List, Optional, Union
1
+ from dataclasses import dataclass
2
+ from enum import Enum
3
+ from typing import Any, Dict, List, Optional, Union
2
4
 
3
5
  from agno.models.message import Message
4
6
 
@@ -17,11 +19,25 @@ class AgentRunException(Exception):
17
19
  self.agent_message = agent_message
18
20
  self.messages = messages
19
21
  self.stop_execution = stop_execution
22
+ self.type = "agent_run_error"
23
+ self.error_id = "agent_run_error"
20
24
 
21
25
 
22
26
  class RetryAgentRun(AgentRunException):
23
27
  """Exception raised when a tool call should be retried."""
24
28
 
29
+ def __init__(
30
+ self,
31
+ exc,
32
+ user_message: Optional[Union[str, Message]] = None,
33
+ agent_message: Optional[Union[str, Message]] = None,
34
+ messages: Optional[List[Union[dict, Message]]] = None,
35
+ ):
36
+ super().__init__(
37
+ exc, user_message=user_message, agent_message=agent_message, messages=messages, stop_execution=False
38
+ )
39
+ self.error_id = "retry_agent_run_error"
40
+
25
41
 
26
42
  class StopAgentRun(AgentRunException):
27
43
  """Exception raised when an agent should stop executing entirely."""
@@ -36,3 +52,129 @@ class StopAgentRun(AgentRunException):
36
52
  super().__init__(
37
53
  exc, user_message=user_message, agent_message=agent_message, messages=messages, stop_execution=True
38
54
  )
55
+ self.error_id = "stop_agent_run_error"
56
+
57
+
58
+ class RunCancelledException(Exception):
59
+ """Exception raised when a run is cancelled."""
60
+
61
+ def __init__(self, message: str = "Operation cancelled by user"):
62
+ super().__init__(message)
63
+ self.type = "run_cancelled_error"
64
+ self.error_id = "run_cancelled_error"
65
+
66
+
67
+ class AgnoError(Exception):
68
+ """Exception raised when an internal error occurs."""
69
+
70
+ def __init__(self, message: str, status_code: int = 500):
71
+ super().__init__(message)
72
+ self.message = message
73
+ self.status_code = status_code
74
+ self.type = "agno_error"
75
+ self.error_id = "agno_error"
76
+
77
+ def __str__(self) -> str:
78
+ return str(self.message)
79
+
80
+
81
+ class ModelAuthenticationError(AgnoError):
82
+ """Raised when model authentication fails."""
83
+
84
+ def __init__(self, message: str, status_code: int = 401, model_name: Optional[str] = None):
85
+ super().__init__(message, status_code)
86
+ self.model_name = model_name
87
+
88
+ self.type = "model_authentication_error"
89
+ self.error_id = "model_authentication_error"
90
+
91
+
92
+ class ModelProviderError(AgnoError):
93
+ """Exception raised when a model provider returns an error."""
94
+
95
+ def __init__(
96
+ self, message: str, status_code: int = 502, model_name: Optional[str] = None, model_id: Optional[str] = None
97
+ ):
98
+ super().__init__(message, status_code)
99
+ self.model_name = model_name
100
+ self.model_id = model_id
101
+
102
+ self.type = "model_provider_error"
103
+ self.error_id = "model_provider_error"
104
+
105
+
106
+ class ModelRateLimitError(ModelProviderError):
107
+ """Exception raised when a model provider returns a rate limit error."""
108
+
109
+ def __init__(
110
+ self, message: str, status_code: int = 429, model_name: Optional[str] = None, model_id: Optional[str] = None
111
+ ):
112
+ super().__init__(message, status_code, model_name, model_id)
113
+ self.error_id = "model_rate_limit_error"
114
+
115
+
116
+ class EvalError(Exception):
117
+ """Exception raised when an evaluation fails."""
118
+
119
+ pass
120
+
121
+
122
+ class CheckTrigger(Enum):
123
+ """Enum for guardrail triggers."""
124
+
125
+ OFF_TOPIC = "off_topic"
126
+ INPUT_NOT_ALLOWED = "input_not_allowed"
127
+ OUTPUT_NOT_ALLOWED = "output_not_allowed"
128
+ VALIDATION_FAILED = "validation_failed"
129
+
130
+ PROMPT_INJECTION = "prompt_injection"
131
+ PII_DETECTED = "pii_detected"
132
+
133
+
134
+ class InputCheckError(Exception):
135
+ """Exception raised when an input check fails."""
136
+
137
+ def __init__(
138
+ self,
139
+ message: str,
140
+ check_trigger: CheckTrigger = CheckTrigger.INPUT_NOT_ALLOWED,
141
+ additional_data: Optional[Dict[str, Any]] = None,
142
+ ):
143
+ super().__init__(message)
144
+ self.type = "input_check_error"
145
+ if isinstance(check_trigger, CheckTrigger):
146
+ self.error_id = check_trigger.value
147
+ else:
148
+ self.error_id = str(check_trigger)
149
+
150
+ self.message = message
151
+ self.check_trigger = check_trigger
152
+ self.additional_data = additional_data
153
+
154
+
155
+ class OutputCheckError(Exception):
156
+ """Exception raised when an output check fails."""
157
+
158
+ def __init__(
159
+ self,
160
+ message: str,
161
+ check_trigger: CheckTrigger = CheckTrigger.OUTPUT_NOT_ALLOWED,
162
+ additional_data: Optional[Dict[str, Any]] = None,
163
+ ):
164
+ super().__init__(message)
165
+ self.type = "output_check_error"
166
+ if isinstance(check_trigger, CheckTrigger):
167
+ self.error_id = check_trigger.value
168
+ else:
169
+ self.error_id = str(check_trigger)
170
+
171
+ self.message = message
172
+ self.check_trigger = check_trigger
173
+ self.additional_data = additional_data
174
+
175
+
176
+ @dataclass
177
+ class RetryableModelProviderError(Exception):
178
+ original_error: Optional[str] = None
179
+ # Guidance message to retry a model invocation after an error
180
+ retry_guidance_message: Optional[str] = None