agno 1.8.2__py3-none-any.whl → 2.0.0__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 (589) hide show
  1. agno/agent/__init__.py +19 -27
  2. agno/agent/agent.py +3143 -4170
  3. agno/api/agent.py +11 -67
  4. agno/api/api.py +5 -46
  5. agno/api/evals.py +8 -19
  6. agno/api/os.py +17 -0
  7. agno/api/routes.py +6 -41
  8. agno/api/schemas/__init__.py +9 -0
  9. agno/api/schemas/agent.py +5 -21
  10. agno/api/schemas/evals.py +7 -16
  11. agno/api/schemas/os.py +14 -0
  12. agno/api/schemas/team.py +5 -21
  13. agno/api/schemas/utils.py +21 -0
  14. agno/api/schemas/workflows.py +11 -7
  15. agno/api/settings.py +53 -0
  16. agno/api/team.py +11 -66
  17. agno/api/workflow.py +28 -0
  18. agno/cloud/aws/base.py +214 -0
  19. agno/cloud/aws/s3/__init__.py +2 -0
  20. agno/cloud/aws/s3/api_client.py +43 -0
  21. agno/cloud/aws/s3/bucket.py +195 -0
  22. agno/cloud/aws/s3/object.py +57 -0
  23. agno/db/__init__.py +24 -0
  24. agno/db/base.py +245 -0
  25. agno/db/dynamo/__init__.py +3 -0
  26. agno/db/dynamo/dynamo.py +1743 -0
  27. agno/db/dynamo/schemas.py +278 -0
  28. agno/db/dynamo/utils.py +684 -0
  29. agno/db/firestore/__init__.py +3 -0
  30. agno/db/firestore/firestore.py +1432 -0
  31. agno/db/firestore/schemas.py +130 -0
  32. agno/db/firestore/utils.py +278 -0
  33. agno/db/gcs_json/__init__.py +3 -0
  34. agno/db/gcs_json/gcs_json_db.py +1001 -0
  35. agno/db/gcs_json/utils.py +194 -0
  36. agno/db/in_memory/__init__.py +3 -0
  37. agno/db/in_memory/in_memory_db.py +882 -0
  38. agno/db/in_memory/utils.py +172 -0
  39. agno/db/json/__init__.py +3 -0
  40. agno/db/json/json_db.py +1045 -0
  41. agno/db/json/utils.py +196 -0
  42. agno/db/migrations/v1_to_v2.py +162 -0
  43. agno/db/mongo/__init__.py +3 -0
  44. agno/db/mongo/mongo.py +1416 -0
  45. agno/db/mongo/schemas.py +77 -0
  46. agno/db/mongo/utils.py +204 -0
  47. agno/db/mysql/__init__.py +3 -0
  48. agno/db/mysql/mysql.py +1719 -0
  49. agno/db/mysql/schemas.py +124 -0
  50. agno/db/mysql/utils.py +297 -0
  51. agno/db/postgres/__init__.py +3 -0
  52. agno/db/postgres/postgres.py +1710 -0
  53. agno/db/postgres/schemas.py +124 -0
  54. agno/db/postgres/utils.py +280 -0
  55. agno/db/redis/__init__.py +3 -0
  56. agno/db/redis/redis.py +1367 -0
  57. agno/db/redis/schemas.py +109 -0
  58. agno/db/redis/utils.py +288 -0
  59. agno/db/schemas/__init__.py +3 -0
  60. agno/db/schemas/evals.py +33 -0
  61. agno/db/schemas/knowledge.py +40 -0
  62. agno/db/schemas/memory.py +46 -0
  63. agno/db/singlestore/__init__.py +3 -0
  64. agno/db/singlestore/schemas.py +116 -0
  65. agno/db/singlestore/singlestore.py +1712 -0
  66. agno/db/singlestore/utils.py +326 -0
  67. agno/db/sqlite/__init__.py +3 -0
  68. agno/db/sqlite/schemas.py +119 -0
  69. agno/db/sqlite/sqlite.py +1676 -0
  70. agno/db/sqlite/utils.py +268 -0
  71. agno/db/utils.py +88 -0
  72. agno/eval/__init__.py +14 -0
  73. agno/eval/accuracy.py +154 -48
  74. agno/eval/performance.py +88 -23
  75. agno/eval/reliability.py +73 -20
  76. agno/eval/utils.py +23 -13
  77. agno/integrations/discord/__init__.py +3 -0
  78. agno/{app → integrations}/discord/client.py +10 -10
  79. agno/knowledge/__init__.py +2 -2
  80. agno/{document → knowledge}/chunking/agentic.py +2 -2
  81. agno/{document → knowledge}/chunking/document.py +2 -2
  82. agno/{document → knowledge}/chunking/fixed.py +3 -3
  83. agno/{document → knowledge}/chunking/markdown.py +2 -2
  84. agno/{document → knowledge}/chunking/recursive.py +2 -2
  85. agno/{document → knowledge}/chunking/row.py +2 -2
  86. agno/knowledge/chunking/semantic.py +59 -0
  87. agno/knowledge/chunking/strategy.py +121 -0
  88. agno/knowledge/content.py +74 -0
  89. agno/knowledge/document/__init__.py +5 -0
  90. agno/{document → knowledge/document}/base.py +12 -2
  91. agno/knowledge/embedder/__init__.py +5 -0
  92. agno/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
  93. agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
  94. agno/{embedder → knowledge/embedder}/base.py +6 -0
  95. agno/{embedder → knowledge/embedder}/cohere.py +72 -1
  96. agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
  97. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  98. agno/{embedder → knowledge/embedder}/google.py +74 -1
  99. agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
  100. agno/{embedder → knowledge/embedder}/jina.py +48 -2
  101. agno/knowledge/embedder/langdb.py +22 -0
  102. agno/knowledge/embedder/mistral.py +139 -0
  103. agno/{embedder → knowledge/embedder}/nebius.py +1 -1
  104. agno/{embedder → knowledge/embedder}/ollama.py +54 -3
  105. agno/knowledge/embedder/openai.py +223 -0
  106. agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
  107. agno/{embedder → knowledge/embedder}/together.py +1 -1
  108. agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
  109. agno/knowledge/knowledge.py +1551 -0
  110. agno/knowledge/reader/__init__.py +7 -0
  111. agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
  112. agno/knowledge/reader/base.py +88 -0
  113. agno/{document → knowledge}/reader/csv_reader.py +47 -65
  114. agno/knowledge/reader/docx_reader.py +83 -0
  115. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  116. agno/{document → knowledge}/reader/json_reader.py +30 -9
  117. agno/{document → knowledge}/reader/markdown_reader.py +58 -9
  118. agno/{document → knowledge}/reader/pdf_reader.py +71 -126
  119. agno/knowledge/reader/reader_factory.py +268 -0
  120. agno/knowledge/reader/s3_reader.py +101 -0
  121. agno/{document → knowledge}/reader/text_reader.py +31 -10
  122. agno/knowledge/reader/url_reader.py +128 -0
  123. agno/knowledge/reader/web_search_reader.py +366 -0
  124. agno/{document → knowledge}/reader/website_reader.py +37 -10
  125. agno/knowledge/reader/wikipedia_reader.py +59 -0
  126. agno/knowledge/reader/youtube_reader.py +78 -0
  127. agno/knowledge/remote_content/remote_content.py +88 -0
  128. agno/{reranker → knowledge/reranker}/base.py +1 -1
  129. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  130. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  131. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  132. agno/knowledge/types.py +30 -0
  133. agno/knowledge/utils.py +169 -0
  134. agno/media.py +269 -268
  135. agno/memory/__init__.py +2 -10
  136. agno/memory/manager.py +1003 -148
  137. agno/models/aimlapi/__init__.py +2 -2
  138. agno/models/aimlapi/aimlapi.py +6 -6
  139. agno/models/anthropic/claude.py +128 -72
  140. agno/models/aws/bedrock.py +107 -175
  141. agno/models/aws/claude.py +64 -18
  142. agno/models/azure/ai_foundry.py +73 -23
  143. agno/models/base.py +346 -290
  144. agno/models/cerebras/cerebras.py +84 -27
  145. agno/models/cohere/chat.py +106 -98
  146. agno/models/google/gemini.py +105 -46
  147. agno/models/groq/groq.py +97 -35
  148. agno/models/huggingface/huggingface.py +92 -27
  149. agno/models/ibm/watsonx.py +72 -13
  150. agno/models/litellm/chat.py +85 -13
  151. agno/models/message.py +46 -151
  152. agno/models/meta/llama.py +85 -49
  153. agno/models/metrics.py +120 -0
  154. agno/models/mistral/mistral.py +90 -21
  155. agno/models/ollama/__init__.py +0 -2
  156. agno/models/ollama/chat.py +85 -47
  157. agno/models/openai/chat.py +154 -37
  158. agno/models/openai/responses.py +178 -105
  159. agno/models/perplexity/perplexity.py +26 -2
  160. agno/models/portkey/portkey.py +0 -7
  161. agno/models/response.py +15 -9
  162. agno/models/utils.py +20 -0
  163. agno/models/vercel/__init__.py +2 -2
  164. agno/models/vercel/v0.py +1 -1
  165. agno/models/vllm/__init__.py +2 -2
  166. agno/models/vllm/vllm.py +3 -3
  167. agno/models/xai/xai.py +10 -10
  168. agno/os/__init__.py +3 -0
  169. agno/os/app.py +497 -0
  170. agno/os/auth.py +47 -0
  171. agno/os/config.py +103 -0
  172. agno/os/interfaces/agui/__init__.py +3 -0
  173. agno/os/interfaces/agui/agui.py +31 -0
  174. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  175. agno/{app → os/interfaces}/agui/utils.py +65 -28
  176. agno/os/interfaces/base.py +21 -0
  177. agno/os/interfaces/slack/__init__.py +3 -0
  178. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  179. agno/os/interfaces/slack/slack.py +32 -0
  180. agno/os/interfaces/whatsapp/__init__.py +3 -0
  181. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  182. agno/os/interfaces/whatsapp/whatsapp.py +29 -0
  183. agno/os/mcp.py +235 -0
  184. agno/os/router.py +1400 -0
  185. agno/os/routers/__init__.py +3 -0
  186. agno/os/routers/evals/__init__.py +3 -0
  187. agno/os/routers/evals/evals.py +393 -0
  188. agno/os/routers/evals/schemas.py +142 -0
  189. agno/os/routers/evals/utils.py +161 -0
  190. agno/os/routers/knowledge/__init__.py +3 -0
  191. agno/os/routers/knowledge/knowledge.py +850 -0
  192. agno/os/routers/knowledge/schemas.py +118 -0
  193. agno/os/routers/memory/__init__.py +3 -0
  194. agno/os/routers/memory/memory.py +410 -0
  195. agno/os/routers/memory/schemas.py +58 -0
  196. agno/os/routers/metrics/__init__.py +3 -0
  197. agno/os/routers/metrics/metrics.py +178 -0
  198. agno/os/routers/metrics/schemas.py +47 -0
  199. agno/os/routers/session/__init__.py +3 -0
  200. agno/os/routers/session/session.py +536 -0
  201. agno/os/schema.py +945 -0
  202. agno/{app/playground → os}/settings.py +7 -15
  203. agno/os/utils.py +270 -0
  204. agno/reasoning/azure_ai_foundry.py +4 -4
  205. agno/reasoning/deepseek.py +4 -4
  206. agno/reasoning/default.py +6 -11
  207. agno/reasoning/groq.py +4 -4
  208. agno/reasoning/helpers.py +4 -6
  209. agno/reasoning/ollama.py +4 -4
  210. agno/reasoning/openai.py +4 -4
  211. agno/run/agent.py +633 -0
  212. agno/run/base.py +53 -77
  213. agno/run/cancel.py +81 -0
  214. agno/run/team.py +243 -96
  215. agno/run/workflow.py +550 -12
  216. agno/session/__init__.py +10 -0
  217. agno/session/agent.py +244 -0
  218. agno/session/summary.py +225 -0
  219. agno/session/team.py +262 -0
  220. agno/{storage/session/v2 → session}/workflow.py +47 -24
  221. agno/team/__init__.py +15 -16
  222. agno/team/team.py +3260 -4824
  223. agno/tools/agentql.py +14 -5
  224. agno/tools/airflow.py +9 -4
  225. agno/tools/api.py +7 -3
  226. agno/tools/apify.py +2 -46
  227. agno/tools/arxiv.py +8 -3
  228. agno/tools/aws_lambda.py +7 -5
  229. agno/tools/aws_ses.py +7 -1
  230. agno/tools/baidusearch.py +4 -1
  231. agno/tools/bitbucket.py +4 -4
  232. agno/tools/brandfetch.py +14 -11
  233. agno/tools/bravesearch.py +4 -1
  234. agno/tools/brightdata.py +43 -23
  235. agno/tools/browserbase.py +13 -4
  236. agno/tools/calcom.py +12 -10
  237. agno/tools/calculator.py +10 -27
  238. agno/tools/cartesia.py +20 -17
  239. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  240. agno/tools/confluence.py +8 -8
  241. agno/tools/crawl4ai.py +7 -1
  242. agno/tools/csv_toolkit.py +9 -8
  243. agno/tools/dalle.py +22 -12
  244. agno/tools/daytona.py +13 -16
  245. agno/tools/decorator.py +6 -3
  246. agno/tools/desi_vocal.py +17 -8
  247. agno/tools/discord.py +11 -8
  248. agno/tools/docker.py +30 -42
  249. agno/tools/duckdb.py +34 -53
  250. agno/tools/duckduckgo.py +8 -7
  251. agno/tools/e2b.py +62 -62
  252. agno/tools/eleven_labs.py +36 -29
  253. agno/tools/email.py +4 -1
  254. agno/tools/evm.py +7 -1
  255. agno/tools/exa.py +19 -14
  256. agno/tools/fal.py +30 -30
  257. agno/tools/file.py +9 -8
  258. agno/tools/financial_datasets.py +25 -44
  259. agno/tools/firecrawl.py +17 -18
  260. agno/tools/function.py +127 -18
  261. agno/tools/giphy.py +23 -11
  262. agno/tools/github.py +48 -126
  263. agno/tools/gmail.py +45 -61
  264. agno/tools/google_bigquery.py +7 -6
  265. agno/tools/google_maps.py +11 -26
  266. agno/tools/googlesearch.py +7 -2
  267. agno/tools/googlesheets.py +21 -17
  268. agno/tools/hackernews.py +9 -5
  269. agno/tools/jina.py +5 -4
  270. agno/tools/jira.py +18 -9
  271. agno/tools/knowledge.py +31 -32
  272. agno/tools/linear.py +18 -33
  273. agno/tools/linkup.py +5 -1
  274. agno/tools/local_file_system.py +8 -5
  275. agno/tools/lumalab.py +32 -20
  276. agno/tools/mcp.py +1 -2
  277. agno/tools/mem0.py +18 -12
  278. agno/tools/memori.py +14 -10
  279. agno/tools/mlx_transcribe.py +3 -2
  280. agno/tools/models/azure_openai.py +33 -15
  281. agno/tools/models/gemini.py +59 -32
  282. agno/tools/models/groq.py +30 -23
  283. agno/tools/models/nebius.py +28 -12
  284. agno/tools/models_labs.py +40 -16
  285. agno/tools/moviepy_video.py +7 -6
  286. agno/tools/neo4j.py +10 -8
  287. agno/tools/newspaper.py +7 -2
  288. agno/tools/newspaper4k.py +8 -3
  289. agno/tools/openai.py +58 -32
  290. agno/tools/openbb.py +12 -11
  291. agno/tools/opencv.py +63 -47
  292. agno/tools/openweather.py +14 -12
  293. agno/tools/pandas.py +11 -3
  294. agno/tools/postgres.py +4 -12
  295. agno/tools/pubmed.py +4 -1
  296. agno/tools/python.py +9 -22
  297. agno/tools/reasoning.py +35 -27
  298. agno/tools/reddit.py +11 -26
  299. agno/tools/replicate.py +55 -42
  300. agno/tools/resend.py +4 -1
  301. agno/tools/scrapegraph.py +15 -14
  302. agno/tools/searxng.py +10 -23
  303. agno/tools/serpapi.py +6 -3
  304. agno/tools/serper.py +13 -4
  305. agno/tools/shell.py +9 -2
  306. agno/tools/slack.py +12 -11
  307. agno/tools/sleep.py +3 -2
  308. agno/tools/spider.py +24 -4
  309. agno/tools/sql.py +7 -6
  310. agno/tools/tavily.py +6 -4
  311. agno/tools/telegram.py +12 -4
  312. agno/tools/todoist.py +11 -31
  313. agno/tools/toolkit.py +1 -1
  314. agno/tools/trafilatura.py +22 -6
  315. agno/tools/trello.py +9 -22
  316. agno/tools/twilio.py +10 -3
  317. agno/tools/user_control_flow.py +6 -1
  318. agno/tools/valyu.py +34 -5
  319. agno/tools/visualization.py +19 -28
  320. agno/tools/webbrowser.py +4 -3
  321. agno/tools/webex.py +11 -7
  322. agno/tools/website.py +15 -46
  323. agno/tools/webtools.py +12 -4
  324. agno/tools/whatsapp.py +5 -9
  325. agno/tools/wikipedia.py +20 -13
  326. agno/tools/x.py +14 -13
  327. agno/tools/yfinance.py +13 -40
  328. agno/tools/youtube.py +26 -20
  329. agno/tools/zendesk.py +7 -2
  330. agno/tools/zep.py +10 -7
  331. agno/tools/zoom.py +10 -9
  332. agno/utils/common.py +1 -19
  333. agno/utils/events.py +100 -123
  334. agno/utils/gemini.py +1 -1
  335. agno/utils/knowledge.py +29 -0
  336. agno/utils/log.py +54 -4
  337. agno/utils/mcp.py +68 -10
  338. agno/utils/media.py +39 -0
  339. agno/utils/message.py +12 -1
  340. agno/utils/models/aws_claude.py +1 -1
  341. agno/utils/models/claude.py +6 -12
  342. agno/utils/models/cohere.py +1 -1
  343. agno/utils/models/mistral.py +8 -7
  344. agno/utils/models/schema_utils.py +3 -3
  345. agno/utils/models/watsonx.py +1 -1
  346. agno/utils/openai.py +1 -1
  347. agno/utils/pprint.py +33 -32
  348. agno/utils/print_response/agent.py +779 -0
  349. agno/utils/print_response/team.py +1669 -0
  350. agno/utils/print_response/workflow.py +1451 -0
  351. agno/utils/prompts.py +14 -14
  352. agno/utils/reasoning.py +87 -0
  353. agno/utils/response.py +42 -42
  354. agno/utils/streamlit.py +481 -0
  355. agno/utils/string.py +8 -22
  356. agno/utils/team.py +50 -0
  357. agno/utils/timer.py +2 -2
  358. agno/vectordb/base.py +33 -21
  359. agno/vectordb/cassandra/cassandra.py +287 -23
  360. agno/vectordb/chroma/chromadb.py +482 -59
  361. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  362. agno/vectordb/couchbase/couchbase.py +309 -29
  363. agno/vectordb/lancedb/lance_db.py +360 -21
  364. agno/vectordb/langchaindb/__init__.py +5 -0
  365. agno/vectordb/langchaindb/langchaindb.py +145 -0
  366. agno/vectordb/lightrag/__init__.py +5 -0
  367. agno/vectordb/lightrag/lightrag.py +374 -0
  368. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  369. agno/vectordb/milvus/milvus.py +242 -32
  370. agno/vectordb/mongodb/mongodb.py +200 -24
  371. agno/vectordb/pgvector/pgvector.py +319 -37
  372. agno/vectordb/pineconedb/pineconedb.py +221 -27
  373. agno/vectordb/qdrant/qdrant.py +334 -14
  374. agno/vectordb/singlestore/singlestore.py +286 -29
  375. agno/vectordb/surrealdb/surrealdb.py +187 -7
  376. agno/vectordb/upstashdb/upstashdb.py +342 -26
  377. agno/vectordb/weaviate/weaviate.py +227 -165
  378. agno/workflow/__init__.py +17 -13
  379. agno/workflow/{v2/condition.py → condition.py} +135 -32
  380. agno/workflow/{v2/loop.py → loop.py} +115 -28
  381. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  382. agno/workflow/{v2/router.py → router.py} +133 -32
  383. agno/workflow/{v2/step.py → step.py} +207 -49
  384. agno/workflow/{v2/steps.py → steps.py} +147 -66
  385. agno/workflow/types.py +482 -0
  386. agno/workflow/workflow.py +2410 -696
  387. agno-2.0.0.dist-info/METADATA +494 -0
  388. agno-2.0.0.dist-info/RECORD +515 -0
  389. agno-2.0.0.dist-info/licenses/LICENSE +201 -0
  390. agno/agent/metrics.py +0 -110
  391. agno/api/app.py +0 -35
  392. agno/api/playground.py +0 -92
  393. agno/api/schemas/app.py +0 -12
  394. agno/api/schemas/playground.py +0 -22
  395. agno/api/schemas/user.py +0 -35
  396. agno/api/schemas/workspace.py +0 -46
  397. agno/api/user.py +0 -160
  398. agno/api/workflows.py +0 -33
  399. agno/api/workspace.py +0 -175
  400. agno/app/agui/__init__.py +0 -3
  401. agno/app/agui/app.py +0 -17
  402. agno/app/agui/sync_router.py +0 -120
  403. agno/app/base.py +0 -186
  404. agno/app/discord/__init__.py +0 -3
  405. agno/app/fastapi/__init__.py +0 -3
  406. agno/app/fastapi/app.py +0 -107
  407. agno/app/fastapi/async_router.py +0 -457
  408. agno/app/fastapi/sync_router.py +0 -448
  409. agno/app/playground/app.py +0 -228
  410. agno/app/playground/async_router.py +0 -1053
  411. agno/app/playground/deploy.py +0 -249
  412. agno/app/playground/operator.py +0 -183
  413. agno/app/playground/schemas.py +0 -223
  414. agno/app/playground/serve.py +0 -55
  415. agno/app/playground/sync_router.py +0 -1045
  416. agno/app/playground/utils.py +0 -46
  417. agno/app/settings.py +0 -15
  418. agno/app/slack/__init__.py +0 -3
  419. agno/app/slack/app.py +0 -19
  420. agno/app/slack/sync_router.py +0 -92
  421. agno/app/utils.py +0 -54
  422. agno/app/whatsapp/__init__.py +0 -3
  423. agno/app/whatsapp/app.py +0 -15
  424. agno/app/whatsapp/sync_router.py +0 -197
  425. agno/cli/auth_server.py +0 -249
  426. agno/cli/config.py +0 -274
  427. agno/cli/console.py +0 -88
  428. agno/cli/credentials.py +0 -23
  429. agno/cli/entrypoint.py +0 -571
  430. agno/cli/operator.py +0 -357
  431. agno/cli/settings.py +0 -96
  432. agno/cli/ws/ws_cli.py +0 -817
  433. agno/constants.py +0 -13
  434. agno/document/__init__.py +0 -5
  435. agno/document/chunking/semantic.py +0 -45
  436. agno/document/chunking/strategy.py +0 -31
  437. agno/document/reader/__init__.py +0 -5
  438. agno/document/reader/base.py +0 -47
  439. agno/document/reader/docx_reader.py +0 -60
  440. agno/document/reader/gcs/pdf_reader.py +0 -44
  441. agno/document/reader/s3/pdf_reader.py +0 -59
  442. agno/document/reader/s3/text_reader.py +0 -63
  443. agno/document/reader/url_reader.py +0 -59
  444. agno/document/reader/youtube_reader.py +0 -58
  445. agno/embedder/__init__.py +0 -5
  446. agno/embedder/langdb.py +0 -80
  447. agno/embedder/mistral.py +0 -82
  448. agno/embedder/openai.py +0 -78
  449. agno/file/__init__.py +0 -5
  450. agno/file/file.py +0 -16
  451. agno/file/local/csv.py +0 -32
  452. agno/file/local/txt.py +0 -19
  453. agno/infra/app.py +0 -240
  454. agno/infra/base.py +0 -144
  455. agno/infra/context.py +0 -20
  456. agno/infra/db_app.py +0 -52
  457. agno/infra/resource.py +0 -205
  458. agno/infra/resources.py +0 -55
  459. agno/knowledge/agent.py +0 -702
  460. agno/knowledge/arxiv.py +0 -33
  461. agno/knowledge/combined.py +0 -36
  462. agno/knowledge/csv.py +0 -144
  463. agno/knowledge/csv_url.py +0 -124
  464. agno/knowledge/document.py +0 -223
  465. agno/knowledge/docx.py +0 -137
  466. agno/knowledge/firecrawl.py +0 -34
  467. agno/knowledge/gcs/__init__.py +0 -0
  468. agno/knowledge/gcs/base.py +0 -39
  469. agno/knowledge/gcs/pdf.py +0 -125
  470. agno/knowledge/json.py +0 -137
  471. agno/knowledge/langchain.py +0 -71
  472. agno/knowledge/light_rag.py +0 -273
  473. agno/knowledge/llamaindex.py +0 -66
  474. agno/knowledge/markdown.py +0 -154
  475. agno/knowledge/pdf.py +0 -164
  476. agno/knowledge/pdf_bytes.py +0 -42
  477. agno/knowledge/pdf_url.py +0 -148
  478. agno/knowledge/s3/__init__.py +0 -0
  479. agno/knowledge/s3/base.py +0 -64
  480. agno/knowledge/s3/pdf.py +0 -33
  481. agno/knowledge/s3/text.py +0 -34
  482. agno/knowledge/text.py +0 -141
  483. agno/knowledge/url.py +0 -46
  484. agno/knowledge/website.py +0 -179
  485. agno/knowledge/wikipedia.py +0 -32
  486. agno/knowledge/youtube.py +0 -35
  487. agno/memory/agent.py +0 -423
  488. agno/memory/classifier.py +0 -104
  489. agno/memory/db/__init__.py +0 -5
  490. agno/memory/db/base.py +0 -42
  491. agno/memory/db/mongodb.py +0 -189
  492. agno/memory/db/postgres.py +0 -203
  493. agno/memory/db/sqlite.py +0 -193
  494. agno/memory/memory.py +0 -22
  495. agno/memory/row.py +0 -36
  496. agno/memory/summarizer.py +0 -201
  497. agno/memory/summary.py +0 -19
  498. agno/memory/team.py +0 -415
  499. agno/memory/v2/__init__.py +0 -2
  500. agno/memory/v2/db/__init__.py +0 -1
  501. agno/memory/v2/db/base.py +0 -42
  502. agno/memory/v2/db/firestore.py +0 -339
  503. agno/memory/v2/db/mongodb.py +0 -196
  504. agno/memory/v2/db/postgres.py +0 -214
  505. agno/memory/v2/db/redis.py +0 -187
  506. agno/memory/v2/db/schema.py +0 -54
  507. agno/memory/v2/db/sqlite.py +0 -209
  508. agno/memory/v2/manager.py +0 -437
  509. agno/memory/v2/memory.py +0 -1097
  510. agno/memory/v2/schema.py +0 -55
  511. agno/memory/v2/summarizer.py +0 -215
  512. agno/memory/workflow.py +0 -38
  513. agno/models/ollama/tools.py +0 -430
  514. agno/models/qwen/__init__.py +0 -5
  515. agno/playground/__init__.py +0 -10
  516. agno/playground/deploy.py +0 -3
  517. agno/playground/playground.py +0 -3
  518. agno/playground/serve.py +0 -3
  519. agno/playground/settings.py +0 -3
  520. agno/reranker/__init__.py +0 -0
  521. agno/run/response.py +0 -467
  522. agno/run/v2/__init__.py +0 -0
  523. agno/run/v2/workflow.py +0 -567
  524. agno/storage/__init__.py +0 -0
  525. agno/storage/agent/__init__.py +0 -0
  526. agno/storage/agent/dynamodb.py +0 -1
  527. agno/storage/agent/json.py +0 -1
  528. agno/storage/agent/mongodb.py +0 -1
  529. agno/storage/agent/postgres.py +0 -1
  530. agno/storage/agent/singlestore.py +0 -1
  531. agno/storage/agent/sqlite.py +0 -1
  532. agno/storage/agent/yaml.py +0 -1
  533. agno/storage/base.py +0 -60
  534. agno/storage/dynamodb.py +0 -673
  535. agno/storage/firestore.py +0 -297
  536. agno/storage/gcs_json.py +0 -261
  537. agno/storage/in_memory.py +0 -234
  538. agno/storage/json.py +0 -237
  539. agno/storage/mongodb.py +0 -328
  540. agno/storage/mysql.py +0 -685
  541. agno/storage/postgres.py +0 -682
  542. agno/storage/redis.py +0 -336
  543. agno/storage/session/__init__.py +0 -16
  544. agno/storage/session/agent.py +0 -64
  545. agno/storage/session/team.py +0 -63
  546. agno/storage/session/v2/__init__.py +0 -5
  547. agno/storage/session/workflow.py +0 -61
  548. agno/storage/singlestore.py +0 -606
  549. agno/storage/sqlite.py +0 -646
  550. agno/storage/workflow/__init__.py +0 -0
  551. agno/storage/workflow/mongodb.py +0 -1
  552. agno/storage/workflow/postgres.py +0 -1
  553. agno/storage/workflow/sqlite.py +0 -1
  554. agno/storage/yaml.py +0 -241
  555. agno/tools/thinking.py +0 -73
  556. agno/utils/defaults.py +0 -57
  557. agno/utils/filesystem.py +0 -39
  558. agno/utils/git.py +0 -52
  559. agno/utils/json_io.py +0 -30
  560. agno/utils/load_env.py +0 -19
  561. agno/utils/py_io.py +0 -19
  562. agno/utils/pyproject.py +0 -18
  563. agno/utils/resource_filter.py +0 -31
  564. agno/workflow/v2/__init__.py +0 -21
  565. agno/workflow/v2/types.py +0 -357
  566. agno/workflow/v2/workflow.py +0 -3313
  567. agno/workspace/__init__.py +0 -0
  568. agno/workspace/config.py +0 -325
  569. agno/workspace/enums.py +0 -6
  570. agno/workspace/helpers.py +0 -52
  571. agno/workspace/operator.py +0 -757
  572. agno/workspace/settings.py +0 -158
  573. agno-1.8.2.dist-info/METADATA +0 -982
  574. agno-1.8.2.dist-info/RECORD +0 -566
  575. agno-1.8.2.dist-info/entry_points.txt +0 -3
  576. agno-1.8.2.dist-info/licenses/LICENSE +0 -375
  577. /agno/{app → db/migrations}/__init__.py +0 -0
  578. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  579. /agno/{cli → integrations}/__init__.py +0 -0
  580. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  581. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  582. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  583. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  584. /agno/{app → os/interfaces}/slack/security.py +0 -0
  585. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  586. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  587. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  588. {agno-1.8.2.dist-info → agno-2.0.0.dist-info}/WHEEL +0 -0
  589. {agno-1.8.2.dist-info → agno-2.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,481 @@
1
+ from datetime import datetime
2
+ from typing import Any, Callable, Dict, List, Optional
3
+
4
+ import streamlit as st
5
+
6
+ from agno.agent import Agent
7
+ from agno.db.base import SessionType
8
+ from agno.models.anthropic import Claude
9
+ from agno.models.google import Gemini
10
+ from agno.models.openai import OpenAIChat
11
+ from agno.utils.log import logger
12
+
13
+
14
+ def add_message(role: str, content: str, tool_calls: Optional[List[Dict[str, Any]]] = None) -> None:
15
+ """Add a message to the session state."""
16
+ if "messages" not in st.session_state:
17
+ st.session_state["messages"] = []
18
+
19
+ message: Dict[str, Any] = {"role": role, "content": content}
20
+ if tool_calls:
21
+ message["tool_calls"] = tool_calls
22
+
23
+ st.session_state["messages"].append(message)
24
+
25
+
26
+ def display_tool_calls(container, tools: List[Any]):
27
+ """Display tool calls in expandable sections."""
28
+ if not tools:
29
+ return
30
+
31
+ with container.container():
32
+ for tool in tools:
33
+ if hasattr(tool, "tool_name"):
34
+ name = tool.tool_name or "Tool"
35
+ args = tool.tool_args or {}
36
+ result = tool.result or ""
37
+ else:
38
+ name = tool.get("tool_name") or tool.get("name") or "Tool"
39
+ args = tool.get("tool_args") or tool.get("args") or {}
40
+ result = tool.get("result") or tool.get("content") or ""
41
+
42
+ with st.expander(f"🛠️ {name.replace('_', ' ')}", expanded=False):
43
+ if args:
44
+ st.markdown("**Arguments:**")
45
+ st.json(args)
46
+ if result:
47
+ st.markdown("**Result:**")
48
+ st.json(result)
49
+
50
+
51
+ def session_selector_widget(agent: Agent, model_id: str, agent_creation_callback: Callable[[str, str], Agent]) -> None:
52
+ """Session selector widget"""
53
+ if not agent.db:
54
+ st.sidebar.info("💡 Database not configured. Sessions will not be saved.")
55
+ return
56
+
57
+ try:
58
+ sessions = agent.db.get_sessions(
59
+ session_type=SessionType.AGENT,
60
+ deserialize=True,
61
+ sort_by="created_at",
62
+ sort_order="desc",
63
+ )
64
+ except Exception as e:
65
+ logger.error(f"Error fetching sessions: {e}")
66
+ st.sidebar.error("Could not load sessions")
67
+ return
68
+
69
+ if not sessions:
70
+ st.sidebar.info("🆕 New Chat - Start your conversation!")
71
+ return
72
+
73
+ # Filter session data
74
+ session_options = []
75
+ session_dict = {}
76
+
77
+ for session in sessions:
78
+ if not hasattr(session, "session_id") or not session.session_id:
79
+ continue
80
+
81
+ session_id = session.session_id
82
+ session_name = None
83
+
84
+ # Extract session name from session_data
85
+ if hasattr(session, "session_data") and session.session_data:
86
+ session_name = session.session_data.get("session_name")
87
+
88
+ name = session_name or session_id
89
+ session_options.append(name)
90
+ session_dict[name] = session_id
91
+
92
+ current_session_id = st.session_state.get("session_id")
93
+ current_selection = None
94
+
95
+ if current_session_id and current_session_id not in [s_id for s_id in session_dict.values()]:
96
+ logger.info(f"New session: {current_session_id}")
97
+ if agent.get_session_name():
98
+ current_display_name = agent.get_session_name()
99
+ else:
100
+ current_display_name = f"{current_session_id[:8]}..."
101
+ session_options.insert(0, current_display_name)
102
+ session_dict[current_display_name] = current_session_id
103
+ current_selection = current_display_name
104
+ st.session_state["is_new_session"] = True
105
+
106
+ for display_name, session_id in session_dict.items():
107
+ if session_id == current_session_id:
108
+ current_selection = display_name
109
+ break
110
+
111
+ display_options = session_options
112
+ selected_index = (
113
+ session_options.index(current_selection)
114
+ if current_selection and current_selection in session_options
115
+ else 0
116
+ if session_options
117
+ else None
118
+ )
119
+
120
+ if not display_options:
121
+ st.sidebar.info("🆕 Start your first conversation!")
122
+ return
123
+
124
+ selected = st.sidebar.selectbox(
125
+ label="Session",
126
+ options=display_options,
127
+ index=selected_index,
128
+ help="Select a session to continue",
129
+ )
130
+
131
+ if selected and selected in session_dict:
132
+ selected_session_id = session_dict[selected]
133
+ if selected_session_id != current_session_id:
134
+ if not st.session_state.get("is_new_session", False):
135
+ st.session_state["is_loading_session"] = True
136
+ try:
137
+ _load_session(selected_session_id, model_id, agent_creation_callback)
138
+ finally:
139
+ # Always clear the loading flag, even if there's an error
140
+ st.session_state["is_loading_session"] = False
141
+ else:
142
+ # Clear the new session flag since we're done with initialization
143
+ st.session_state["is_new_session"] = False
144
+
145
+ # Rename session
146
+ if agent.session_id:
147
+ if "session_edit_mode" not in st.session_state:
148
+ st.session_state.session_edit_mode = False
149
+
150
+ current_name = agent.get_session_name() or agent.session_id
151
+
152
+ if not st.session_state.session_edit_mode:
153
+ col1, col2 = st.sidebar.columns([3, 1])
154
+ with col1:
155
+ st.write(f"**Session:** {current_name}")
156
+ with col2:
157
+ if st.button("✎", help="Rename session", key="rename_session_button"):
158
+ st.session_state.session_edit_mode = True
159
+ st.rerun()
160
+ else:
161
+ new_name = st.sidebar.text_input("Enter new name:", value=current_name, key="session_name_input")
162
+
163
+ col1, col2 = st.sidebar.columns([1, 1])
164
+ with col1:
165
+ if st.button(
166
+ "💾 Save",
167
+ type="primary",
168
+ use_container_width=True,
169
+ key="save_session_name",
170
+ ):
171
+ if new_name and new_name.strip():
172
+ try:
173
+ result = agent.set_session_name(session_name=new_name.strip())
174
+
175
+ if result:
176
+ logger.info(f"Session renamed to: {new_name.strip()}")
177
+ # Clear any cached session data to ensure fresh reload
178
+ if hasattr(agent, "_agent_session") and agent._agent_session:
179
+ agent._agent_session = None
180
+ st.session_state.session_edit_mode = False
181
+ st.sidebar.success("Session renamed!")
182
+ st.rerun()
183
+ except Exception as e:
184
+ logger.error(f"Error renaming session: {e}")
185
+ st.sidebar.error(f"Error: {str(e)}")
186
+ else:
187
+ st.sidebar.error("Please enter a valid name")
188
+
189
+ with col2:
190
+ if st.button("❌ Cancel", use_container_width=True, key="cancel_session_rename"):
191
+ st.session_state.session_edit_mode = False
192
+ st.rerun()
193
+
194
+
195
+ def _load_session(session_id: str, model_id: str, agent_creation_callback: Callable[[str, str], Agent]):
196
+ try:
197
+ logger.info(f"Creating agent with session_id: {session_id}")
198
+ new_agent = agent_creation_callback(model_id, session_id)
199
+
200
+ st.session_state["agent"] = new_agent
201
+ st.session_state["session_id"] = session_id
202
+ st.session_state["messages"] = []
203
+ st.session_state["current_model"] = model_id # Keep current_model in sync
204
+
205
+ try:
206
+ if new_agent.db:
207
+ selected_session = new_agent.db.get_session(
208
+ session_id=session_id, session_type=SessionType.AGENT, deserialize=True
209
+ )
210
+ else:
211
+ selected_session = None
212
+
213
+ # Recreate the chat history
214
+ if selected_session:
215
+ if hasattr(selected_session, "runs") and selected_session.runs:
216
+ for run_idx, run in enumerate(selected_session.runs):
217
+ messages = getattr(run, "messages", None)
218
+
219
+ if messages:
220
+ user_msg = None
221
+ assistant_msg = None
222
+ tool_calls = []
223
+
224
+ for msg_idx, message in enumerate(messages):
225
+ if not hasattr(message, "role") or not hasattr(message, "content"):
226
+ continue
227
+
228
+ role = message.role
229
+ content = str(message.content) if message.content else ""
230
+
231
+ if role == "user":
232
+ if content and content.strip():
233
+ user_msg = content.strip()
234
+ elif role == "assistant":
235
+ if content and content.strip() and content.strip().lower() != "none":
236
+ assistant_msg = content
237
+
238
+ # Display tool calls for this run
239
+ if hasattr(run, "tools") and run.tools:
240
+ tool_calls = run.tools
241
+
242
+ # Add messages to chat history
243
+ if user_msg:
244
+ add_message("user", user_msg)
245
+ if assistant_msg:
246
+ add_message("assistant", assistant_msg, tool_calls)
247
+
248
+ else:
249
+ logger.warning(f"No session found in database for session_id: {session_id}")
250
+
251
+ except Exception as e:
252
+ logger.warning(f"Could not load chat history: {e}")
253
+
254
+ st.rerun()
255
+
256
+ except Exception as e:
257
+ logger.error(f"Error loading session: {e}")
258
+ st.sidebar.error(f"Error loading session: {str(e)}")
259
+
260
+
261
+ def display_response(agent: Agent, question: str) -> None:
262
+ """Handle agent response with streaming and tool call display."""
263
+ with st.chat_message("assistant"):
264
+ tool_calls_container = st.empty()
265
+ resp_container = st.empty()
266
+ with st.spinner("🤔 Thinking..."):
267
+ response = ""
268
+ try:
269
+ # Run the agent and stream the response
270
+ run_response = agent.run(question, stream=True)
271
+ for resp_chunk in run_response:
272
+ try:
273
+ # Display tool calls if available
274
+ if hasattr(resp_chunk, "tool") and resp_chunk.tool:
275
+ display_tool_calls(tool_calls_container, [resp_chunk.tool])
276
+ except Exception as tool_error:
277
+ logger.warning(f"Error displaying tool calls: {tool_error}")
278
+
279
+ if resp_chunk.content is not None:
280
+ content = str(resp_chunk.content)
281
+
282
+ if not (
283
+ content.strip().endswith("completed in") or "completed in" in content and "s." in content
284
+ ):
285
+ response += content
286
+ resp_container.markdown(response)
287
+
288
+ try:
289
+ if hasattr(agent, "run_response") and agent.run_response and hasattr(agent.run_response, "tools"):
290
+ add_message("assistant", response, agent.run_response.tools)
291
+ else:
292
+ add_message("assistant", response)
293
+ except Exception as add_msg_error:
294
+ logger.warning(f"Error adding message with tools: {add_msg_error}")
295
+ add_message("assistant", response)
296
+
297
+ except Exception as e:
298
+ st.error(f"Sorry, I encountered an error: {str(e)}")
299
+
300
+
301
+ def display_chat_messages() -> None:
302
+ """Display all chat messages from session state."""
303
+ if "messages" not in st.session_state:
304
+ return
305
+
306
+ for message in st.session_state["messages"]:
307
+ if message["role"] in ["user", "assistant"]:
308
+ content = message["content"]
309
+ with st.chat_message(message["role"]):
310
+ # Display tool calls
311
+ if "tool_calls" in message and message["tool_calls"]:
312
+ display_tool_calls(st.container(), message["tool_calls"])
313
+
314
+ if content is not None and str(content).strip() and str(content).strip().lower() != "none":
315
+ st.markdown(content)
316
+
317
+
318
+ def initialize_agent(model_id: str, agent_creation_callback: Callable[[str, Optional[str]], Agent]) -> Agent:
319
+ """Initialize or get agent with proper session management."""
320
+ if "agent" not in st.session_state or st.session_state["agent"] is None:
321
+ # First time initialization - get existing session_id if any
322
+ session_id = st.session_state.get("session_id")
323
+ agent = agent_creation_callback(model_id, session_id)
324
+ st.session_state["agent"] = agent
325
+ st.session_state["current_model"] = model_id
326
+
327
+ return agent
328
+ else:
329
+ return st.session_state["agent"]
330
+
331
+
332
+ def reset_session_state(agent: Agent) -> None:
333
+ """Update session state."""
334
+ print(f"Resetting session state for agent: {agent.session_id}")
335
+ if agent.session_id is not None:
336
+ st.session_state["session_id"] = agent.session_id
337
+
338
+ if "messages" not in st.session_state:
339
+ st.session_state["messages"] = []
340
+
341
+
342
+ def knowledge_base_info_widget(agent: Agent) -> None:
343
+ """Display knowledge base information widget."""
344
+ if not agent.knowledge:
345
+ st.sidebar.info("No knowledge base configured")
346
+ return
347
+
348
+ vector_db = getattr(agent.knowledge, "vector_db", None)
349
+ if not vector_db:
350
+ st.sidebar.info("No vector db configured")
351
+ return
352
+
353
+ try:
354
+ doc_count = vector_db.get_count()
355
+ if doc_count == 0:
356
+ st.sidebar.info("💡 Upload documents to populate the knowledge base")
357
+ else:
358
+ st.sidebar.metric("Documents Loaded", doc_count)
359
+ except Exception as e:
360
+ logger.error(f"Error getting knowledge base info: {e}")
361
+ st.sidebar.warning("Could not retrieve knowledge base information")
362
+
363
+
364
+ def export_chat_history(app_name: str = "Chat") -> str:
365
+ """Export chat history to markdown."""
366
+ if "messages" not in st.session_state or not st.session_state["messages"]:
367
+ return "# Chat History\n\n*No messages to export*"
368
+
369
+ title = f"{app_name} Chat History"
370
+ for msg in st.session_state["messages"]:
371
+ if msg.get("role") == "user" and msg.get("content"):
372
+ title = msg["content"][:100]
373
+ if len(msg["content"]) > 100:
374
+ title += "..."
375
+ break
376
+
377
+ chat_text = f"# {title}\n\n"
378
+ chat_text += f"**Exported:** {datetime.now().strftime('%B %d, %Y at %I:%M %p')}\n\n"
379
+ chat_text += "---\n\n"
380
+
381
+ for msg in st.session_state["messages"]:
382
+ role = msg.get("role", "")
383
+ content = msg.get("content", "")
384
+
385
+ if not content or str(content).strip().lower() == "none":
386
+ continue
387
+
388
+ role_display = "## 🙋 User" if role == "user" else "## 🤖 Assistant"
389
+ chat_text += f"{role_display}\n\n{content}\n\n---\n\n"
390
+ return chat_text
391
+
392
+
393
+ def get_model_from_id(model_id: str):
394
+ """Get a model instance from a model ID string."""
395
+ if model_id.startswith("openai:"):
396
+ return OpenAIChat(id=model_id.split("openai:")[1])
397
+ elif model_id.startswith("anthropic:"):
398
+ return Claude(id=model_id.split("anthropic:")[1])
399
+ elif model_id.startswith("google:"):
400
+ return Gemini(id=model_id.split("google:")[1])
401
+ else:
402
+ return OpenAIChat(id="gpt-4o")
403
+
404
+
405
+ def get_model_with_provider(model_name: str):
406
+ """Get a model instance by inferring the correct provider from the model name.
407
+
408
+ Args:
409
+ model_name: Model name (e.g., "gpt-4o", "claude-4-sonnet", "gemini-2.5-pro")
410
+
411
+ Returns:
412
+ Model instance with correct provider
413
+ """
414
+ if ":" in model_name:
415
+ return get_model_from_id(model_name)
416
+
417
+ model_lower = model_name.lower()
418
+
419
+ if any(pattern in model_lower for pattern in ["gpt", "o1", "o3"]):
420
+ return get_model_from_id(f"openai:{model_name}")
421
+
422
+ elif "claude" in model_lower:
423
+ return get_model_from_id(f"anthropic:{model_name}")
424
+
425
+ elif "gemini" in model_lower:
426
+ return get_model_from_id(f"google:{model_name}")
427
+
428
+ else:
429
+ return get_model_from_id(f"openai:{model_name}")
430
+
431
+
432
+ def about_section(description: str):
433
+ """About section"""
434
+ st.sidebar.markdown("---")
435
+ st.sidebar.markdown("### ℹ️ About")
436
+ st.sidebar.markdown(f"""
437
+ {description}
438
+
439
+ Built with:
440
+ - 🚀 Agno
441
+ - 💫 Streamlit
442
+ """)
443
+
444
+
445
+ MODELS = [
446
+ "gpt-4o",
447
+ "o3-mini",
448
+ "gpt-5",
449
+ "claude-4-sonnet",
450
+ "gemini-2.5-pro",
451
+ ]
452
+
453
+
454
+ COMMON_CSS = """
455
+ <style>
456
+ .main-title {
457
+ text-align: center;
458
+ background: linear-gradient(45deg, #FF4B2B, #FF416C);
459
+ -webkit-background-clip: text;
460
+ -webkit-text-fill-color: transparent;
461
+ font-size: 3em;
462
+ font-weight: bold;
463
+ padding: 1em 0;
464
+ }
465
+ .subtitle {
466
+ text-align: center;
467
+ color: #666;
468
+ margin-bottom: 2em;
469
+ }
470
+ .stButton button {
471
+ width: 100%;
472
+ border-radius: 20px;
473
+ margin: 0.2em 0;
474
+ transition: all 0.3s ease;
475
+ }
476
+ .stButton button:hover {
477
+ transform: translateY(-2px);
478
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
479
+ }
480
+ </style>
481
+ """
agno/utils/string.py CHANGED
@@ -27,20 +27,6 @@ def is_valid_uuid(uuid_str: str) -> bool:
27
27
  return False
28
28
 
29
29
 
30
- def safe_content_hash(content: str) -> str:
31
- """
32
- Return an MD5 hash of the input string, replacing null bytes and invalid surrogates for safe hashing.
33
- """
34
- cleaned_content = content.replace("\x00", "\ufffd")
35
- try:
36
- content_hash = hashlib.md5(cleaned_content.encode("utf-8")).hexdigest()
37
- except UnicodeEncodeError:
38
- cleaned_content = "".join("\ufffd" if "\ud800" <= c <= "\udfff" else c for c in cleaned_content)
39
- content_hash = hashlib.md5(cleaned_content.encode("utf-8")).hexdigest()
40
-
41
- return content_hash
42
-
43
-
44
30
  def url_safe_string(input_string):
45
31
  # Replace spaces with dashes
46
32
  safe_string = input_string.replace(" ", "-")
@@ -130,13 +116,13 @@ def _clean_json_content(content: str) -> str:
130
116
  return content
131
117
 
132
118
 
133
- def _parse_individual_json(content: str, response_model: Type[BaseModel]) -> Optional[BaseModel]:
119
+ def _parse_individual_json(content: str, output_schema: Type[BaseModel]) -> Optional[BaseModel]:
134
120
  """Parse individual JSON objects from content and merge them based on response model fields."""
135
121
  candidate_jsons = _extract_json_objects(content)
136
122
  merged_data: dict = {}
137
123
 
138
124
  # Get the expected fields from the response model
139
- model_fields = response_model.model_fields if hasattr(response_model, "model_fields") else {}
125
+ model_fields = output_schema.model_fields if hasattr(output_schema, "model_fields") else {}
140
126
 
141
127
  for candidate in candidate_jsons:
142
128
  try:
@@ -161,13 +147,13 @@ def _parse_individual_json(content: str, response_model: Type[BaseModel]) -> Opt
161
147
  return None
162
148
 
163
149
  try:
164
- return response_model.model_validate(merged_data)
150
+ return output_schema.model_validate(merged_data)
165
151
  except ValidationError as e:
166
152
  logger.warning("Validation failed on merged data: %s", e)
167
153
  return None
168
154
 
169
155
 
170
- def parse_response_model_str(content: str, response_model: Type[BaseModel]) -> Optional[BaseModel]:
156
+ def parse_response_model_str(content: str, output_schema: Type[BaseModel]) -> Optional[BaseModel]:
171
157
  structured_output = None
172
158
 
173
159
  # Clean content first to simplify all parsing attempts
@@ -175,12 +161,12 @@ def parse_response_model_str(content: str, response_model: Type[BaseModel]) -> O
175
161
 
176
162
  try:
177
163
  # First attempt: direct JSON validation on cleaned content
178
- structured_output = response_model.model_validate_json(cleaned_content)
164
+ structured_output = output_schema.model_validate_json(cleaned_content)
179
165
  except (ValidationError, json.JSONDecodeError):
180
166
  try:
181
167
  # Second attempt: Parse as Python dict
182
168
  data = json.loads(cleaned_content)
183
- structured_output = response_model.model_validate(data)
169
+ structured_output = output_schema.model_validate(data)
184
170
  except (ValidationError, json.JSONDecodeError) as e:
185
171
  logger.warning(f"Failed to parse cleaned JSON: {e}")
186
172
 
@@ -191,13 +177,13 @@ def parse_response_model_str(content: str, response_model: Type[BaseModel]) -> O
191
177
  # Single JSON object - try to parse it directly
192
178
  try:
193
179
  data = json.loads(candidate_jsons[0])
194
- structured_output = response_model.model_validate(data)
180
+ structured_output = output_schema.model_validate(data)
195
181
  except (ValidationError, json.JSONDecodeError):
196
182
  pass
197
183
 
198
184
  if structured_output is None:
199
185
  # Final attempt: Handle concatenated JSON objects with field merging
200
- structured_output = _parse_individual_json(cleaned_content, response_model)
186
+ structured_output = _parse_individual_json(cleaned_content, output_schema)
201
187
  if structured_output is None:
202
188
  logger.warning("All parsing attempts failed.")
203
189
 
agno/utils/team.py ADDED
@@ -0,0 +1,50 @@
1
+ from typing import TYPE_CHECKING, Optional, Union
2
+
3
+ from agno.agent import Agent
4
+ from agno.utils.string import is_valid_uuid, url_safe_string
5
+
6
+ if TYPE_CHECKING:
7
+ from agno.team.team import Team
8
+
9
+
10
+ def format_member_agent_task(
11
+ task_description: str,
12
+ expected_output: Optional[str] = None,
13
+ team_member_interactions_str: Optional[str] = None,
14
+ ) -> str:
15
+ member_agent_task = "You are a member of a team of agents. Your goal is to complete the following task:"
16
+ member_agent_task += f"\n\n<task>\n{task_description}\n</task>"
17
+
18
+ if expected_output is not None:
19
+ member_agent_task += f"\n\n<expected_output>\n{expected_output}\n</expected_output>"
20
+
21
+ if team_member_interactions_str:
22
+ member_agent_task += f"\n\n{team_member_interactions_str}"
23
+
24
+ return member_agent_task
25
+
26
+
27
+ def get_member_id(member: Union[Agent, "Team"]) -> str:
28
+ """
29
+ Get the ID of a member
30
+
31
+ If the member has an agent_id or team_id, use that if it is not a valid UUID.
32
+ Then if the member has a name, convert that to a URL safe string.
33
+ Then if the member has the default UUID ID, use that.
34
+ Otherwise, return None.
35
+ """
36
+ from agno.team.team import Team
37
+
38
+ if isinstance(member, Agent) and member.id is not None and (not is_valid_uuid(member.id)):
39
+ url_safe_member_id = url_safe_string(member.id)
40
+ elif isinstance(member, Team) and member.id is not None and (not is_valid_uuid(member.id)):
41
+ url_safe_member_id = url_safe_string(member.id)
42
+ elif member.name is not None:
43
+ url_safe_member_id = url_safe_string(member.name)
44
+ elif isinstance(member, Agent) and member.id is not None:
45
+ url_safe_member_id = member.id
46
+ elif isinstance(member, Team) and member.id is not None:
47
+ url_safe_member_id = member.id
48
+ else:
49
+ url_safe_member_id = None
50
+ return url_safe_member_id
agno/utils/timer.py CHANGED
@@ -24,11 +24,11 @@ class Timer:
24
24
  self.elapsed_time = self.end_time - self.start_time
25
25
  return self.end_time
26
26
 
27
- def __enter__(self):
27
+ def __enter__(self) -> "Timer":
28
28
  self.start_time = perf_counter()
29
29
  return self
30
30
 
31
- def __exit__(self, *args):
31
+ def __exit__(self, *args) -> None:
32
32
  self.end_time = perf_counter()
33
33
  if self.start_time is not None:
34
34
  self.elapsed_time = self.end_time - self.start_time