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,779 @@
1
+ import asyncio
2
+ import gc
3
+ import tracemalloc
4
+ from dataclasses import dataclass, field
5
+ from os import getenv
6
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Union
7
+ from uuid import uuid4
8
+
9
+ from agno.db.base import AsyncBaseDb, BaseDb
10
+ from agno.db.schemas.evals import EvalType
11
+ from agno.eval.utils import async_log_eval, log_eval_run, store_result_in_file
12
+ from agno.utils.log import log_debug, set_log_level_to_debug, set_log_level_to_info
13
+ from agno.utils.timer import Timer
14
+
15
+ if TYPE_CHECKING:
16
+ from rich.console import Console
17
+
18
+
19
+ @dataclass
20
+ class PerformanceResult:
21
+ """
22
+ Holds run-time and memory-usage statistics.
23
+ In addition to average, min, max, std dev, we add median and percentile metrics
24
+ for a more robust understanding.
25
+ """
26
+
27
+ # Run time performance in seconds
28
+ run_times: List[float] = field(default_factory=list)
29
+ avg_run_time: float = field(init=False)
30
+ min_run_time: float = field(init=False)
31
+ max_run_time: float = field(init=False)
32
+ std_dev_run_time: float = field(init=False)
33
+ median_run_time: float = field(init=False)
34
+ p95_run_time: float = field(init=False)
35
+
36
+ # Memory performance in MiB
37
+ memory_usages: List[float] = field(default_factory=list)
38
+ avg_memory_usage: float = field(init=False)
39
+ min_memory_usage: float = field(init=False)
40
+ max_memory_usage: float = field(init=False)
41
+ std_dev_memory_usage: float = field(init=False)
42
+ median_memory_usage: float = field(init=False)
43
+ p95_memory_usage: float = field(init=False)
44
+
45
+ def __post_init__(self):
46
+ self.compute_stats()
47
+
48
+ def compute_stats(self):
49
+ """Compute a variety of statistics for both runtime and memory usage."""
50
+ import statistics
51
+
52
+ def safe_stats(data: List[float]):
53
+ """Compute stats for a non-empty list of floats."""
54
+ data_sorted = sorted(data) # ensure data is sorted for correct percentile
55
+ avg = statistics.mean(data_sorted)
56
+ mn = data_sorted[0]
57
+ mx = data_sorted[-1]
58
+ std = statistics.stdev(data_sorted) if len(data_sorted) > 1 else 0
59
+ med = statistics.median(data_sorted)
60
+ # For 95th percentile, use statistics.quantiles
61
+ p95 = statistics.quantiles(data_sorted, n=100)[94] if len(data_sorted) > 1 else 0
62
+ return avg, mn, mx, std, med, p95
63
+
64
+ # Populate runtime stats
65
+ if self.run_times:
66
+ (
67
+ self.avg_run_time,
68
+ self.min_run_time,
69
+ self.max_run_time,
70
+ self.std_dev_run_time,
71
+ self.median_run_time,
72
+ self.p95_run_time,
73
+ ) = safe_stats(self.run_times)
74
+ else:
75
+ self.avg_run_time = 0
76
+ self.min_run_time = 0
77
+ self.max_run_time = 0
78
+ self.std_dev_run_time = 0
79
+ self.median_run_time = 0
80
+ self.p95_run_time = 0
81
+
82
+ # Populate memory stats
83
+ if self.memory_usages:
84
+ (
85
+ self.avg_memory_usage,
86
+ self.min_memory_usage,
87
+ self.max_memory_usage,
88
+ self.std_dev_memory_usage,
89
+ self.median_memory_usage,
90
+ self.p95_memory_usage,
91
+ ) = safe_stats(self.memory_usages)
92
+ else:
93
+ self.avg_memory_usage = 0
94
+ self.min_memory_usage = 0
95
+ self.max_memory_usage = 0
96
+ self.std_dev_memory_usage = 0
97
+ self.median_memory_usage = 0
98
+ self.p95_memory_usage = 0
99
+
100
+ def print_summary(
101
+ self, console: Optional["Console"] = None, measure_memory: bool = True, measure_runtime: bool = True
102
+ ):
103
+ """
104
+ Prints a summary table of the computed stats.
105
+ """
106
+ from rich.console import Console
107
+ from rich.table import Table
108
+
109
+ if console is None:
110
+ console = Console()
111
+
112
+ # Create performance table
113
+ perf_table = Table(title="Performance Summary", show_header=True, header_style="bold magenta")
114
+ perf_table.add_column("Metric", style="cyan")
115
+ if measure_runtime:
116
+ perf_table.add_column("Time (seconds)", style="green")
117
+ if measure_memory:
118
+ perf_table.add_column("Memory (MiB)", style="yellow")
119
+
120
+ # Add rows
121
+ if measure_runtime and measure_memory:
122
+ perf_table.add_row("Average", f"{self.avg_run_time:.6f}", f"{self.avg_memory_usage:.6f}")
123
+ perf_table.add_row("Minimum", f"{self.min_run_time:.6f}", f"{self.min_memory_usage:.6f}")
124
+ perf_table.add_row("Maximum", f"{self.max_run_time:.6f}", f"{self.max_memory_usage:.6f}")
125
+ perf_table.add_row("Std Dev", f"{self.std_dev_run_time:.6f}", f"{self.std_dev_memory_usage:.6f}")
126
+ perf_table.add_row("Median", f"{self.median_run_time:.6f}", f"{self.median_memory_usage:.6f}")
127
+ perf_table.add_row("95th %ile", f"{self.p95_run_time:.6f}", f"{self.p95_memory_usage:.6f}")
128
+ elif measure_runtime:
129
+ perf_table.add_row("Average", f"{self.avg_run_time:.6f}")
130
+ perf_table.add_row("Minimum", f"{self.min_run_time:.6f}")
131
+ perf_table.add_row("Maximum", f"{self.max_run_time:.6f}")
132
+ perf_table.add_row("Std Dev", f"{self.std_dev_run_time:.6f}")
133
+ perf_table.add_row("Median", f"{self.median_run_time:.6f}")
134
+ perf_table.add_row("95th %ile", f"{self.p95_run_time:.6f}")
135
+ elif measure_memory:
136
+ perf_table.add_row("Average", f"{self.avg_memory_usage:.6f}")
137
+ perf_table.add_row("Minimum", f"{self.min_memory_usage:.6f}")
138
+ perf_table.add_row("Maximum", f"{self.max_memory_usage:.6f}")
139
+ perf_table.add_row("Std Dev", f"{self.std_dev_memory_usage:.6f}")
140
+ perf_table.add_row("Median", f"{self.median_memory_usage:.6f}")
141
+ perf_table.add_row("95th %ile", f"{self.p95_memory_usage:.6f}")
142
+
143
+ console.print(perf_table)
144
+
145
+ def print_results(
146
+ self, console: Optional["Console"] = None, measure_memory: bool = True, measure_runtime: bool = True
147
+ ):
148
+ """
149
+ Prints individual run results in tabular form.
150
+ """
151
+ from rich.console import Console
152
+ from rich.table import Table
153
+
154
+ if console is None:
155
+ console = Console()
156
+
157
+ # Create runs table
158
+ results_table = Table(title="Individual Runs", show_header=True, header_style="bold magenta")
159
+ results_table.add_column("Run #", style="cyan")
160
+ if measure_runtime:
161
+ results_table.add_column("Time (seconds)", style="green")
162
+ if measure_memory:
163
+ results_table.add_column("Memory (MiB)", style="yellow")
164
+
165
+ # Add rows
166
+ for i in range(len(self.run_times) or len(self.memory_usages)):
167
+ if measure_runtime and measure_memory:
168
+ results_table.add_row(str(i + 1), f"{self.run_times[i]:.6f}", f"{self.memory_usages[i]:.6f}")
169
+ elif measure_runtime:
170
+ results_table.add_row(str(i + 1), f"{self.run_times[i]:.6f}")
171
+ elif measure_memory:
172
+ results_table.add_row(str(i + 1), f"{self.memory_usages[i]:.6f}")
173
+ else:
174
+ results_table.add_row(str(i + 1))
175
+
176
+ console.print(results_table)
177
+
178
+
179
+ @dataclass
180
+ class PerformanceEval:
181
+ """
182
+ Evaluate the performance of a function by measuring run time and peak memory usage.
183
+
184
+ - Warm-up runs are included to avoid measuring overhead on the first execution(s).
185
+ - Debug mode can show top memory allocations using tracemalloc snapshots.
186
+ - Optionally, you can enable cProfile for CPU profiling stats.
187
+ """
188
+
189
+ # Function to evaluate
190
+ func: Callable
191
+ measure_runtime: bool = True
192
+ measure_memory: bool = True
193
+
194
+ # Evaluation name
195
+ name: Optional[str] = None
196
+ # Evaluation UUID
197
+ eval_id: str = field(default_factory=lambda: str(uuid4()))
198
+ # Number of warm-up runs (not included in final stats)
199
+ warmup_runs: Optional[int] = 10
200
+ # Number of measured iterations
201
+ num_iterations: int = 50
202
+ # Result of the evaluation
203
+ result: Optional[PerformanceResult] = None
204
+
205
+ # Print summary of results
206
+ print_summary: bool = False
207
+ # Print detailed results
208
+ print_results: bool = False
209
+ # Print detailed memory growth analysis
210
+ memory_growth_tracking: bool = False
211
+ # Number of memory allocations to track
212
+ top_n_memory_allocations: int = 5
213
+
214
+ # Agent and Team information
215
+ agent_id: Optional[str] = None
216
+ team_id: Optional[str] = None
217
+ model_id: Optional[str] = None
218
+ model_provider: Optional[str] = None
219
+
220
+ # If set, results will be saved in the given file path
221
+ file_path_to_save_results: Optional[str] = None
222
+ # Enable debug logs
223
+ debug_mode: bool = getenv("AGNO_DEBUG", "false").lower() == "true"
224
+ # The database to store Evaluation results
225
+ db: Optional[Union[BaseDb, AsyncBaseDb]] = None
226
+
227
+ # Telemetry settings
228
+ # telemetry=True logs minimal telemetry for analytics
229
+ # This helps us improve our Evals and provide better support
230
+ telemetry: bool = True
231
+
232
+ def _measure_time(self) -> float:
233
+ """Measure execution time for a single run."""
234
+ timer = Timer()
235
+
236
+ timer.start()
237
+ self.func()
238
+ timer.stop()
239
+ self._set_log_level() # Set log level incase function changed it
240
+
241
+ return timer.elapsed
242
+
243
+ async def _async_measure_time(self) -> float:
244
+ """Measure execution time for a single run of the contextual async function."""
245
+ timer = Timer()
246
+
247
+ timer.start()
248
+ await self.func()
249
+ timer.stop()
250
+ self._set_log_level() # Set log level incase function changed it
251
+
252
+ return timer.elapsed
253
+
254
+ def _measure_memory(self, baseline: float) -> float:
255
+ """
256
+ Measures peak memory usage using tracemalloc.
257
+ Subtracts the provided 'baseline' to compute an adjusted usage.
258
+ """
259
+
260
+ # Clear memory before measurement
261
+ gc.collect()
262
+ # Start tracing memory
263
+ tracemalloc.start()
264
+
265
+ self.func()
266
+
267
+ # Get peak memory usage
268
+ current, peak = tracemalloc.get_traced_memory()
269
+
270
+ # Stop tracing memory
271
+ tracemalloc.stop()
272
+
273
+ self._set_log_level() # Set log level incase function changed it
274
+
275
+ # Convert to MiB and subtract baseline
276
+ peak_mib = peak / 1024 / 1024
277
+ adjusted_usage = max(0, peak_mib - baseline)
278
+
279
+ if self.debug_mode:
280
+ log_debug(f"[DEBUG] Raw peak usage: {peak_mib:.6f} MiB, Adjusted: {adjusted_usage:.6f} MiB")
281
+
282
+ return adjusted_usage
283
+
284
+ def _parse_eval_run_data(self) -> dict:
285
+ """Parse the evaluation result into a dictionary with the data we want for monitoring."""
286
+ if self.result is None:
287
+ return {}
288
+
289
+ return {
290
+ "result": {
291
+ "avg_run_time": self.result.avg_run_time,
292
+ "min_run_time": self.result.min_run_time,
293
+ "max_run_time": self.result.max_run_time,
294
+ "std_dev_run_time": self.result.std_dev_run_time,
295
+ "median_run_time": self.result.median_run_time,
296
+ "p95_run_time": self.result.p95_run_time,
297
+ "avg_memory_usage": self.result.avg_memory_usage,
298
+ "min_memory_usage": self.result.min_memory_usage,
299
+ "max_memory_usage": self.result.max_memory_usage,
300
+ "std_dev_memory_usage": self.result.std_dev_memory_usage,
301
+ "median_memory_usage": self.result.median_memory_usage,
302
+ "p95_memory_usage": self.result.p95_memory_usage,
303
+ },
304
+ "runs": [
305
+ {"runtime": runtime, "memory": memory_usage}
306
+ for runtime, memory_usage in zip(self.result.run_times, self.result.memory_usages)
307
+ ],
308
+ }
309
+
310
+ async def _async_measure_memory(self, baseline: float) -> float:
311
+ """
312
+ Measures peak memory usage using tracemalloc for async functions.
313
+ Subtracts the provided 'baseline' to compute an adjusted usage.
314
+ """
315
+
316
+ # Clear memory before measurement
317
+ gc.collect()
318
+ # Start tracing memory
319
+ tracemalloc.start()
320
+
321
+ await self.func()
322
+
323
+ # Get peak memory usage
324
+ current, peak = tracemalloc.get_traced_memory()
325
+
326
+ # Stop tracing memory
327
+ tracemalloc.stop()
328
+ self._set_log_level() # Set log level incase function changed it
329
+
330
+ # Convert to MiB and subtract baseline
331
+ peak_mib = peak / 1024 / 1024
332
+ adjusted_usage = max(0, peak_mib - baseline)
333
+
334
+ if self.debug_mode:
335
+ log_debug(f"[DEBUG] Raw peak usage: {peak_mib:.6f} MiB, Adjusted: {adjusted_usage:.6f} MiB")
336
+
337
+ return adjusted_usage
338
+
339
+ def _compute_tracemalloc_baseline(self, samples: int = 3) -> float:
340
+ """
341
+ Runs tracemalloc multiple times with an empty function to establish
342
+ a stable average baseline for memory usage in MiB.
343
+ """
344
+
345
+ def empty_func():
346
+ return
347
+
348
+ results = []
349
+ for _ in range(samples):
350
+ gc.collect()
351
+ tracemalloc.start()
352
+ empty_func()
353
+ _, peak = tracemalloc.get_traced_memory()
354
+ tracemalloc.stop()
355
+ results.append(peak / 1024 / 1024)
356
+
357
+ return sum(results) / len(results) if results else 0
358
+
359
+ def _set_log_level(self):
360
+ if self.debug_mode:
361
+ set_log_level_to_debug()
362
+ else:
363
+ set_log_level_to_info()
364
+
365
+ def _compare_memory_snapshots(self, snapshot1, snapshot2, top_n: int):
366
+ """
367
+ Compare two memory snapshots to identify what's causing memory growth.
368
+ """
369
+ if self.debug_mode:
370
+ log_debug("[DEBUG] Memory growth analysis:")
371
+
372
+ # Compare snapshots to find new allocations
373
+ stats = snapshot2.compare_to(snapshot1, "lineno")
374
+
375
+ log_debug(f"[DEBUG] Top {top_n} memory growth sources:")
376
+ growth_found = False
377
+ for stat in stats[:top_n]:
378
+ if stat.size_diff > 0: # Only show growth
379
+ growth_found = True
380
+ log_debug(f" +{stat.size_diff / 1024 / 1024:.1f} MiB: {stat.count_diff} new blocks")
381
+ log_debug(f" {stat.traceback.format()}")
382
+
383
+ if not growth_found:
384
+ log_debug(" No significant memory growth detected between snapshots")
385
+
386
+ # Show total growth
387
+ total_growth = sum(stat.size_diff for stat in stats if stat.size_diff > 0)
388
+ total_shrinkage = sum(abs(stat.size_diff) for stat in stats if stat.size_diff < 0)
389
+ log_debug(f"[DEBUG] Total memory growth: {total_growth / 1024 / 1024:.1f} MiB")
390
+ log_debug(f"[DEBUG] Total memory freed: {total_shrinkage / 1024 / 1024:.1f} MiB")
391
+ log_debug(f"[DEBUG] Net memory change: {(total_growth - total_shrinkage) / 1024 / 1024:.1f} MiB")
392
+
393
+ def _measure_memory_with_growth_tracking(
394
+ self, baseline: float, previous_snapshot=None
395
+ ) -> tuple[float, tracemalloc.Snapshot]:
396
+ """
397
+ Enhanced memory measurement that tracks growth between runs.
398
+ Returns (adjusted_usage, current_snapshot)
399
+ """
400
+ # Clear memory before measurement
401
+ gc.collect()
402
+ # Start tracing memory
403
+ tracemalloc.start()
404
+
405
+ self.func()
406
+
407
+ # Get peak memory usage
408
+ current, peak = tracemalloc.get_traced_memory()
409
+ # Take snapshot before stopping
410
+ current_snapshot = tracemalloc.take_snapshot()
411
+ # Stop tracing memory
412
+ tracemalloc.stop()
413
+
414
+ self._set_log_level() # Set log level incase function changed it
415
+
416
+ # Convert to MiB and subtract baseline
417
+ peak_mib = peak / 1024 / 1024
418
+ adjusted_usage = max(0, peak_mib - baseline)
419
+
420
+ if self.debug_mode and current_snapshot:
421
+ log_debug(f"[DEBUG] Raw peak usage: {peak_mib:.6f} MiB, Adjusted: {adjusted_usage:.6f} MiB")
422
+
423
+ # Compare with previous snapshot if available
424
+ if previous_snapshot is not None:
425
+ self._compare_memory_snapshots(previous_snapshot, current_snapshot, self.top_n_memory_allocations)
426
+ else:
427
+ # Get detailed memory allocation statistics
428
+ top_stats = current_snapshot.statistics("lineno")
429
+
430
+ log_debug(f"[DEBUG] Top {self.top_n_memory_allocations} memory allocations:")
431
+ for stat in top_stats[: self.top_n_memory_allocations]:
432
+ log_debug(f" {stat.count} blocks: {stat.size / 1024 / 1024:.1f} MiB")
433
+ log_debug(f" {stat.traceback.format()}")
434
+
435
+ return adjusted_usage, current_snapshot
436
+
437
+ async def _async_measure_memory_with_growth_tracking(
438
+ self, baseline: float, previous_snapshot=None
439
+ ) -> tuple[float, tracemalloc.Snapshot]:
440
+ """
441
+ Enhanced async memory measurement that tracks growth between runs.
442
+ Returns (adjusted_usage, current_snapshot)
443
+ """
444
+ # Clear memory before measurement
445
+ gc.collect()
446
+ # Start tracing memory
447
+ tracemalloc.start()
448
+
449
+ await self.func()
450
+
451
+ # Get peak memory usage
452
+ current, peak = tracemalloc.get_traced_memory()
453
+ # Take snapshot before stopping
454
+ current_snapshot = tracemalloc.take_snapshot()
455
+ # Stop tracing memory
456
+ tracemalloc.stop()
457
+
458
+ self._set_log_level() # Set log level incase function changed it
459
+
460
+ # Convert to MiB and subtract baseline
461
+ peak_mib = peak / 1024 / 1024
462
+ adjusted_usage = max(0, peak_mib - baseline)
463
+
464
+ if self.debug_mode and current_snapshot:
465
+ log_debug(f"[DEBUG] Raw peak usage: {peak_mib:.6f} MiB, Adjusted: {adjusted_usage:.6f} MiB")
466
+
467
+ # Compare with previous snapshot if available
468
+ if previous_snapshot is not None:
469
+ self._compare_memory_snapshots(previous_snapshot, current_snapshot, self.top_n_memory_allocations)
470
+ else:
471
+ # Get detailed memory allocation statistics
472
+ top_stats = current_snapshot.statistics("lineno")
473
+
474
+ log_debug(f"[DEBUG] Top {self.top_n_memory_allocations} memory allocations:")
475
+ for stat in top_stats[: self.top_n_memory_allocations]:
476
+ log_debug(f" {stat.count} blocks: {stat.size / 1024 / 1024:.1f} MiB")
477
+ log_debug(f" {stat.traceback.format()}")
478
+
479
+ return adjusted_usage, current_snapshot
480
+
481
+ def run(
482
+ self, *, print_summary: bool = False, print_results: bool = False, memory_growth_tracking: bool = False
483
+ ) -> PerformanceResult:
484
+ """
485
+ Main method to run the performance evaluation.
486
+ 1. Do optional warm-up runs.
487
+ 2. Measure runtime
488
+ 3. Measure memory
489
+ 4. Collect results
490
+ 5. Save results if requested
491
+ 6. Print results as requested
492
+ 7. Log results to the Agno platform if requested
493
+ """
494
+ if isinstance(self.db, AsyncBaseDb):
495
+ raise ValueError("run() is not supported with an async DB. Please use arun() instead.")
496
+
497
+ from rich.console import Console
498
+ from rich.live import Live
499
+ from rich.status import Status
500
+
501
+ # Generate unique run_id for this execution (don't modify self.eval_id due to concurrency)
502
+ run_id = str(uuid4())
503
+
504
+ run_times = []
505
+ memory_usages = []
506
+ previous_snapshot = None
507
+
508
+ self._set_log_level()
509
+
510
+ log_debug(f"************ Evaluation Start: {run_id} ************")
511
+
512
+ # Add a spinner while running the evaluations
513
+ console = Console()
514
+ with Live(console=console, transient=True) as live_log:
515
+ # 1. Do optional warm-up runs.
516
+ if self.warmup_runs is not None:
517
+ for i in range(self.warmup_runs):
518
+ status = Status(f"Warm-up run {i + 1}/{self.warmup_runs}...", spinner="dots", speed=1.0)
519
+ live_log.update(status)
520
+ self.func() # Simply run the function without measuring
521
+ self._set_log_level() # Set log level incase function changed it
522
+ status.stop()
523
+
524
+ # 2. Measure runtime
525
+ if self.measure_runtime:
526
+ for i in range(self.num_iterations):
527
+ status = Status(
528
+ f"Runtime measurement {i + 1}/{self.num_iterations}...",
529
+ spinner="dots",
530
+ speed=1.0,
531
+ refresh_per_second=10,
532
+ )
533
+ live_log.update(status)
534
+ # Measure runtime
535
+ elapsed_time = self._measure_time()
536
+ run_times.append(elapsed_time)
537
+
538
+ log_debug(f"Run {i + 1} - Time taken: {elapsed_time:.6f} seconds")
539
+ status.stop()
540
+
541
+ # 3. Measure memory
542
+ if self.measure_memory:
543
+ # 3.1 Compute memory baseline
544
+ memory_baseline = 0.0
545
+ memory_baseline = self._compute_tracemalloc_baseline()
546
+ log_debug(f"Computed memory baseline: {memory_baseline:.6f} MiB")
547
+
548
+ for i in range(self.num_iterations):
549
+ status = Status(
550
+ f"Memory measurement {i + 1}/{self.num_iterations}...",
551
+ spinner="dots",
552
+ speed=1.0,
553
+ refresh_per_second=10,
554
+ )
555
+ live_log.update(status)
556
+
557
+ # Measure memory
558
+ if self.memory_growth_tracking or memory_growth_tracking:
559
+ usage, current_snapshot = self._measure_memory_with_growth_tracking(
560
+ memory_baseline, previous_snapshot
561
+ )
562
+
563
+ # Update previous snapshot for next iteration
564
+ previous_snapshot = current_snapshot
565
+
566
+ else:
567
+ usage = self._measure_memory(memory_baseline)
568
+ memory_usages.append(usage)
569
+ log_debug(f"Run {i + 1} - Memory usage: {usage:.6f} MiB (adjusted)")
570
+
571
+ status.stop()
572
+
573
+ # 4. Collect results
574
+ self.result = PerformanceResult(run_times=run_times, memory_usages=memory_usages)
575
+
576
+ # 5. Save result to file if requested
577
+ if self.file_path_to_save_results is not None and self.result is not None:
578
+ store_result_in_file(
579
+ file_path=self.file_path_to_save_results,
580
+ name=self.name,
581
+ eval_id=self.eval_id,
582
+ result=self.result,
583
+ )
584
+
585
+ # 6. Print results if requested
586
+ if self.print_results or print_results:
587
+ self.result.print_results(console, measure_memory=self.measure_memory, measure_runtime=self.measure_runtime)
588
+ if self.print_summary or print_summary:
589
+ self.result.print_summary(console, measure_memory=self.measure_memory, measure_runtime=self.measure_runtime)
590
+
591
+ # 7. Log results to the Agno platform if requested
592
+ if self.db:
593
+ eval_input = {
594
+ "num_iterations": self.num_iterations,
595
+ "warmup_runs": self.warmup_runs,
596
+ }
597
+
598
+ log_eval_run(
599
+ db=self.db,
600
+ run_id=self.eval_id, # type: ignore
601
+ run_data=self._parse_eval_run_data(),
602
+ eval_type=EvalType.PERFORMANCE,
603
+ name=self.name if self.name is not None else None,
604
+ evaluated_component_name=self.func.__name__,
605
+ agent_id=self.agent_id,
606
+ team_id=self.team_id,
607
+ model_id=self.model_id,
608
+ model_provider=self.model_provider,
609
+ eval_input=eval_input,
610
+ )
611
+
612
+ if self.telemetry:
613
+ from agno.api.evals import EvalRunCreate, create_eval_run_telemetry
614
+
615
+ create_eval_run_telemetry(
616
+ eval_run=EvalRunCreate(
617
+ run_id=self.eval_id, eval_type=EvalType.PERFORMANCE, data=self._get_telemetry_data()
618
+ ),
619
+ )
620
+
621
+ log_debug(f"*********** Evaluation End: {run_id} ***********")
622
+ return self.result
623
+
624
+ async def arun(
625
+ self, *, print_summary: bool = False, print_results: bool = False, memory_growth_tracking: bool = False
626
+ ) -> PerformanceResult:
627
+ """
628
+ Async method to run the performance evaluation of async functions.
629
+ 1. Do optional warm-up runs.
630
+ 2. Measure runtime
631
+ 3. Measure memory
632
+ 4. Collect results
633
+ 5. Save results if requested
634
+ 6. Print results as requested
635
+ 7. Log results to the Agno platform if requested
636
+ """
637
+ # Validate the function to evaluate is async.
638
+ if not asyncio.iscoroutinefunction(self.func):
639
+ raise ValueError(
640
+ f"The provided function ({self.func.__name__}) is not async. Use the run() method for sync functions."
641
+ )
642
+
643
+ from rich.console import Console
644
+ from rich.live import Live
645
+ from rich.status import Status
646
+
647
+ # Generate unique run_id for this execution (don't modify self.eval_id due to concurrency)
648
+ run_id = str(uuid4())
649
+
650
+ run_times = []
651
+ memory_usages = []
652
+ previous_snapshot = None
653
+
654
+ self._set_log_level()
655
+
656
+ log_debug(f"************ Evaluation Start: {run_id} ************")
657
+
658
+ # Add a spinner while running the evaluations
659
+ console = Console()
660
+ with Live(console=console, transient=True) as live_log:
661
+ # 1. Do optional warm-up runs.
662
+ if self.warmup_runs is not None:
663
+ for i in range(self.warmup_runs):
664
+ status = Status(f"Warm-up run {i + 1}/{self.warmup_runs}...", spinner="dots", speed=1.0)
665
+ live_log.update(status)
666
+ await self.func() # Simply run the function without measuring
667
+ self._set_log_level() # Set log level incase function changed it
668
+ status.stop()
669
+
670
+ # 2. Measure runtime
671
+ if self.measure_runtime:
672
+ for i in range(self.num_iterations):
673
+ status = Status(
674
+ f"Runtime measurement {i + 1}/{self.num_iterations}...",
675
+ spinner="dots",
676
+ speed=1.0,
677
+ refresh_per_second=10,
678
+ )
679
+ live_log.update(status)
680
+ # Measure runtime
681
+ elapsed_time = await self._async_measure_time()
682
+ run_times.append(elapsed_time)
683
+
684
+ log_debug(f"Run {i + 1} - Time taken: {elapsed_time:.6f} seconds")
685
+ status.stop()
686
+
687
+ # 3. Measure memory
688
+ if self.measure_memory:
689
+ # 3.1 Compute memory baseline
690
+ memory_baseline = 0.0
691
+ memory_baseline = self._compute_tracemalloc_baseline()
692
+ log_debug(f"Computed memory baseline: {memory_baseline:.6f} MiB")
693
+
694
+ for i in range(self.num_iterations):
695
+ status = Status(
696
+ f"Memory measurement {i + 1}/{self.num_iterations}...",
697
+ spinner="dots",
698
+ speed=1.0,
699
+ refresh_per_second=10,
700
+ )
701
+ live_log.update(status)
702
+
703
+ # Measure memory
704
+ if self.memory_growth_tracking or memory_growth_tracking:
705
+ usage, current_snapshot = await self._async_measure_memory_with_growth_tracking(
706
+ memory_baseline, previous_snapshot
707
+ )
708
+
709
+ # Update previous snapshot for next iteration
710
+ previous_snapshot = current_snapshot
711
+
712
+ else:
713
+ usage = await self._async_measure_memory(memory_baseline)
714
+ memory_usages.append(usage)
715
+ log_debug(f"Run {i + 1} - Memory usage: {usage:.6f} MiB (adjusted)")
716
+
717
+ status.stop()
718
+
719
+ # 4. Collect results
720
+ self.result = PerformanceResult(run_times=run_times, memory_usages=memory_usages)
721
+
722
+ # 5. Save result to file if requested
723
+ if self.file_path_to_save_results is not None and self.result is not None:
724
+ store_result_in_file(
725
+ file_path=self.file_path_to_save_results,
726
+ name=self.name,
727
+ eval_id=self.eval_id,
728
+ result=self.result,
729
+ )
730
+
731
+ # 6. Print results if requested
732
+ if self.print_results or print_results:
733
+ self.result.print_results(console, measure_memory=self.measure_memory, measure_runtime=self.measure_runtime)
734
+ if self.print_summary or print_summary:
735
+ self.result.print_summary(console, measure_memory=self.measure_memory, measure_runtime=self.measure_runtime)
736
+
737
+ # 7. Log results to the Agno platform if requested
738
+ if self.db:
739
+ eval_input = {
740
+ "num_iterations": self.num_iterations,
741
+ "warmup_runs": self.warmup_runs,
742
+ }
743
+
744
+ await async_log_eval(
745
+ db=self.db,
746
+ run_id=self.eval_id, # type: ignore
747
+ run_data=self._parse_eval_run_data(),
748
+ eval_type=EvalType.PERFORMANCE,
749
+ name=self.name if self.name is not None else None,
750
+ evaluated_component_name=self.func.__name__,
751
+ agent_id=self.agent_id,
752
+ team_id=self.team_id,
753
+ model_id=self.model_id,
754
+ model_provider=self.model_provider,
755
+ eval_input=eval_input,
756
+ )
757
+
758
+ if self.telemetry:
759
+ from agno.api.evals import EvalRunCreate, async_create_eval_run_telemetry
760
+
761
+ await async_create_eval_run_telemetry(
762
+ eval_run=EvalRunCreate(
763
+ run_id=self.eval_id, eval_type=EvalType.PERFORMANCE, data=self._get_telemetry_data()
764
+ ),
765
+ )
766
+
767
+ log_debug(f"*********** Evaluation End: {run_id} ***********")
768
+ return self.result
769
+
770
+ def _get_telemetry_data(self) -> Dict[str, Any]:
771
+ """Get the telemetry data for the evaluation"""
772
+ return {
773
+ "model_id": self.model_id,
774
+ "model_provider": self.model_provider,
775
+ "num_iterations": self.num_iterations,
776
+ "warmup_runs": self.warmup_runs,
777
+ "measure_memory": self.measure_memory,
778
+ "measure_runtime": self.measure_runtime,
779
+ }