agno 1.8.1__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 (590) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +3143 -4170
  4. agno/api/agent.py +11 -67
  5. agno/api/api.py +5 -46
  6. agno/api/evals.py +8 -19
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -41
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +5 -21
  11. agno/api/schemas/evals.py +7 -16
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +5 -21
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +11 -7
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +11 -66
  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/db/__init__.py +24 -0
  25. agno/db/base.py +245 -0
  26. agno/db/dynamo/__init__.py +3 -0
  27. agno/db/dynamo/dynamo.py +1743 -0
  28. agno/db/dynamo/schemas.py +278 -0
  29. agno/db/dynamo/utils.py +684 -0
  30. agno/db/firestore/__init__.py +3 -0
  31. agno/db/firestore/firestore.py +1432 -0
  32. agno/db/firestore/schemas.py +130 -0
  33. agno/db/firestore/utils.py +278 -0
  34. agno/db/gcs_json/__init__.py +3 -0
  35. agno/db/gcs_json/gcs_json_db.py +1001 -0
  36. agno/db/gcs_json/utils.py +194 -0
  37. agno/db/in_memory/__init__.py +3 -0
  38. agno/db/in_memory/in_memory_db.py +882 -0
  39. agno/db/in_memory/utils.py +172 -0
  40. agno/db/json/__init__.py +3 -0
  41. agno/db/json/json_db.py +1045 -0
  42. agno/db/json/utils.py +196 -0
  43. agno/db/migrations/v1_to_v2.py +162 -0
  44. agno/db/mongo/__init__.py +3 -0
  45. agno/db/mongo/mongo.py +1416 -0
  46. agno/db/mongo/schemas.py +77 -0
  47. agno/db/mongo/utils.py +204 -0
  48. agno/db/mysql/__init__.py +3 -0
  49. agno/db/mysql/mysql.py +1719 -0
  50. agno/db/mysql/schemas.py +124 -0
  51. agno/db/mysql/utils.py +297 -0
  52. agno/db/postgres/__init__.py +3 -0
  53. agno/db/postgres/postgres.py +1710 -0
  54. agno/db/postgres/schemas.py +124 -0
  55. agno/db/postgres/utils.py +280 -0
  56. agno/db/redis/__init__.py +3 -0
  57. agno/db/redis/redis.py +1367 -0
  58. agno/db/redis/schemas.py +109 -0
  59. agno/db/redis/utils.py +288 -0
  60. agno/db/schemas/__init__.py +3 -0
  61. agno/db/schemas/evals.py +33 -0
  62. agno/db/schemas/knowledge.py +40 -0
  63. agno/db/schemas/memory.py +46 -0
  64. agno/db/singlestore/__init__.py +3 -0
  65. agno/db/singlestore/schemas.py +116 -0
  66. agno/db/singlestore/singlestore.py +1712 -0
  67. agno/db/singlestore/utils.py +326 -0
  68. agno/db/sqlite/__init__.py +3 -0
  69. agno/db/sqlite/schemas.py +119 -0
  70. agno/db/sqlite/sqlite.py +1676 -0
  71. agno/db/sqlite/utils.py +268 -0
  72. agno/db/utils.py +88 -0
  73. agno/eval/__init__.py +14 -0
  74. agno/eval/accuracy.py +154 -48
  75. agno/eval/performance.py +88 -23
  76. agno/eval/reliability.py +73 -20
  77. agno/eval/utils.py +23 -13
  78. agno/integrations/discord/__init__.py +3 -0
  79. agno/{app → integrations}/discord/client.py +15 -11
  80. agno/knowledge/__init__.py +2 -2
  81. agno/{document → knowledge}/chunking/agentic.py +2 -2
  82. agno/{document → knowledge}/chunking/document.py +2 -2
  83. agno/{document → knowledge}/chunking/fixed.py +3 -3
  84. agno/{document → knowledge}/chunking/markdown.py +2 -2
  85. agno/{document → knowledge}/chunking/recursive.py +2 -2
  86. agno/{document → knowledge}/chunking/row.py +2 -2
  87. agno/knowledge/chunking/semantic.py +59 -0
  88. agno/knowledge/chunking/strategy.py +121 -0
  89. agno/knowledge/content.py +74 -0
  90. agno/knowledge/document/__init__.py +5 -0
  91. agno/{document → knowledge/document}/base.py +12 -2
  92. agno/knowledge/embedder/__init__.py +5 -0
  93. agno/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
  94. agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
  95. agno/{embedder → knowledge/embedder}/base.py +6 -0
  96. agno/{embedder → knowledge/embedder}/cohere.py +72 -1
  97. agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
  98. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  99. agno/{embedder → knowledge/embedder}/google.py +74 -1
  100. agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
  101. agno/{embedder → knowledge/embedder}/jina.py +48 -2
  102. agno/knowledge/embedder/langdb.py +22 -0
  103. agno/knowledge/embedder/mistral.py +139 -0
  104. agno/{embedder → knowledge/embedder}/nebius.py +1 -1
  105. agno/{embedder → knowledge/embedder}/ollama.py +54 -3
  106. agno/knowledge/embedder/openai.py +223 -0
  107. agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
  108. agno/{embedder → knowledge/embedder}/together.py +1 -1
  109. agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
  110. agno/knowledge/knowledge.py +1551 -0
  111. agno/knowledge/reader/__init__.py +7 -0
  112. agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
  113. agno/knowledge/reader/base.py +88 -0
  114. agno/{document → knowledge}/reader/csv_reader.py +47 -65
  115. agno/knowledge/reader/docx_reader.py +83 -0
  116. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  117. agno/{document → knowledge}/reader/json_reader.py +30 -9
  118. agno/{document → knowledge}/reader/markdown_reader.py +58 -9
  119. agno/{document → knowledge}/reader/pdf_reader.py +71 -126
  120. agno/knowledge/reader/reader_factory.py +268 -0
  121. agno/knowledge/reader/s3_reader.py +101 -0
  122. agno/{document → knowledge}/reader/text_reader.py +31 -10
  123. agno/knowledge/reader/url_reader.py +128 -0
  124. agno/knowledge/reader/web_search_reader.py +366 -0
  125. agno/{document → knowledge}/reader/website_reader.py +37 -10
  126. agno/knowledge/reader/wikipedia_reader.py +59 -0
  127. agno/knowledge/reader/youtube_reader.py +78 -0
  128. agno/knowledge/remote_content/remote_content.py +88 -0
  129. agno/{reranker → knowledge/reranker}/base.py +1 -1
  130. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  131. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  132. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  133. agno/knowledge/types.py +30 -0
  134. agno/knowledge/utils.py +169 -0
  135. agno/media.py +269 -268
  136. agno/memory/__init__.py +2 -10
  137. agno/memory/manager.py +1003 -148
  138. agno/models/aimlapi/__init__.py +2 -2
  139. agno/models/aimlapi/aimlapi.py +6 -6
  140. agno/models/anthropic/claude.py +131 -131
  141. agno/models/aws/bedrock.py +110 -182
  142. agno/models/aws/claude.py +64 -18
  143. agno/models/azure/ai_foundry.py +73 -23
  144. agno/models/base.py +346 -290
  145. agno/models/cerebras/cerebras.py +84 -27
  146. agno/models/cohere/chat.py +106 -98
  147. agno/models/google/gemini.py +105 -46
  148. agno/models/groq/groq.py +97 -35
  149. agno/models/huggingface/huggingface.py +92 -27
  150. agno/models/ibm/watsonx.py +72 -13
  151. agno/models/litellm/chat.py +85 -13
  152. agno/models/message.py +46 -151
  153. agno/models/meta/llama.py +85 -49
  154. agno/models/metrics.py +120 -0
  155. agno/models/mistral/mistral.py +90 -21
  156. agno/models/ollama/__init__.py +0 -2
  157. agno/models/ollama/chat.py +85 -47
  158. agno/models/openai/chat.py +154 -37
  159. agno/models/openai/responses.py +178 -105
  160. agno/models/perplexity/perplexity.py +26 -2
  161. agno/models/portkey/portkey.py +0 -7
  162. agno/models/response.py +15 -9
  163. agno/models/utils.py +20 -0
  164. agno/models/vercel/__init__.py +2 -2
  165. agno/models/vercel/v0.py +1 -1
  166. agno/models/vllm/__init__.py +2 -2
  167. agno/models/vllm/vllm.py +3 -3
  168. agno/models/xai/xai.py +10 -10
  169. agno/os/__init__.py +3 -0
  170. agno/os/app.py +497 -0
  171. agno/os/auth.py +47 -0
  172. agno/os/config.py +103 -0
  173. agno/os/interfaces/agui/__init__.py +3 -0
  174. agno/os/interfaces/agui/agui.py +31 -0
  175. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  176. agno/{app → os/interfaces}/agui/utils.py +77 -33
  177. agno/os/interfaces/base.py +21 -0
  178. agno/os/interfaces/slack/__init__.py +3 -0
  179. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  180. agno/os/interfaces/slack/slack.py +32 -0
  181. agno/os/interfaces/whatsapp/__init__.py +3 -0
  182. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  183. agno/os/interfaces/whatsapp/whatsapp.py +29 -0
  184. agno/os/mcp.py +235 -0
  185. agno/os/router.py +1400 -0
  186. agno/os/routers/__init__.py +3 -0
  187. agno/os/routers/evals/__init__.py +3 -0
  188. agno/os/routers/evals/evals.py +393 -0
  189. agno/os/routers/evals/schemas.py +142 -0
  190. agno/os/routers/evals/utils.py +161 -0
  191. agno/os/routers/knowledge/__init__.py +3 -0
  192. agno/os/routers/knowledge/knowledge.py +850 -0
  193. agno/os/routers/knowledge/schemas.py +118 -0
  194. agno/os/routers/memory/__init__.py +3 -0
  195. agno/os/routers/memory/memory.py +410 -0
  196. agno/os/routers/memory/schemas.py +58 -0
  197. agno/os/routers/metrics/__init__.py +3 -0
  198. agno/os/routers/metrics/metrics.py +178 -0
  199. agno/os/routers/metrics/schemas.py +47 -0
  200. agno/os/routers/session/__init__.py +3 -0
  201. agno/os/routers/session/session.py +536 -0
  202. agno/os/schema.py +945 -0
  203. agno/{app/playground → os}/settings.py +7 -15
  204. agno/os/utils.py +270 -0
  205. agno/reasoning/azure_ai_foundry.py +4 -4
  206. agno/reasoning/deepseek.py +4 -4
  207. agno/reasoning/default.py +6 -11
  208. agno/reasoning/groq.py +4 -4
  209. agno/reasoning/helpers.py +4 -6
  210. agno/reasoning/ollama.py +4 -4
  211. agno/reasoning/openai.py +4 -4
  212. agno/run/agent.py +633 -0
  213. agno/run/base.py +53 -77
  214. agno/run/cancel.py +81 -0
  215. agno/run/team.py +243 -96
  216. agno/run/workflow.py +550 -12
  217. agno/session/__init__.py +10 -0
  218. agno/session/agent.py +244 -0
  219. agno/session/summary.py +225 -0
  220. agno/session/team.py +262 -0
  221. agno/{storage/session/v2 → session}/workflow.py +47 -24
  222. agno/team/__init__.py +15 -16
  223. agno/team/team.py +3260 -4824
  224. agno/tools/agentql.py +14 -5
  225. agno/tools/airflow.py +9 -4
  226. agno/tools/api.py +7 -3
  227. agno/tools/apify.py +2 -46
  228. agno/tools/arxiv.py +8 -3
  229. agno/tools/aws_lambda.py +7 -5
  230. agno/tools/aws_ses.py +7 -1
  231. agno/tools/baidusearch.py +4 -1
  232. agno/tools/bitbucket.py +4 -4
  233. agno/tools/brandfetch.py +14 -11
  234. agno/tools/bravesearch.py +4 -1
  235. agno/tools/brightdata.py +43 -23
  236. agno/tools/browserbase.py +13 -4
  237. agno/tools/calcom.py +12 -10
  238. agno/tools/calculator.py +10 -27
  239. agno/tools/cartesia.py +20 -17
  240. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  241. agno/tools/confluence.py +8 -8
  242. agno/tools/crawl4ai.py +7 -1
  243. agno/tools/csv_toolkit.py +9 -8
  244. agno/tools/dalle.py +22 -12
  245. agno/tools/daytona.py +13 -16
  246. agno/tools/decorator.py +6 -3
  247. agno/tools/desi_vocal.py +17 -8
  248. agno/tools/discord.py +11 -8
  249. agno/tools/docker.py +30 -42
  250. agno/tools/duckdb.py +34 -53
  251. agno/tools/duckduckgo.py +8 -7
  252. agno/tools/e2b.py +62 -62
  253. agno/tools/eleven_labs.py +36 -29
  254. agno/tools/email.py +4 -1
  255. agno/tools/evm.py +7 -1
  256. agno/tools/exa.py +19 -14
  257. agno/tools/fal.py +30 -30
  258. agno/tools/file.py +9 -8
  259. agno/tools/financial_datasets.py +25 -44
  260. agno/tools/firecrawl.py +22 -22
  261. agno/tools/function.py +127 -18
  262. agno/tools/giphy.py +23 -11
  263. agno/tools/github.py +48 -126
  264. agno/tools/gmail.py +45 -61
  265. agno/tools/google_bigquery.py +7 -6
  266. agno/tools/google_maps.py +11 -26
  267. agno/tools/googlesearch.py +7 -2
  268. agno/tools/googlesheets.py +21 -17
  269. agno/tools/hackernews.py +9 -5
  270. agno/tools/jina.py +5 -4
  271. agno/tools/jira.py +18 -9
  272. agno/tools/knowledge.py +31 -32
  273. agno/tools/linear.py +19 -34
  274. agno/tools/linkup.py +5 -1
  275. agno/tools/local_file_system.py +8 -5
  276. agno/tools/lumalab.py +32 -20
  277. agno/tools/mcp.py +1 -2
  278. agno/tools/mem0.py +18 -12
  279. agno/tools/memori.py +14 -10
  280. agno/tools/mlx_transcribe.py +3 -2
  281. agno/tools/models/azure_openai.py +33 -15
  282. agno/tools/models/gemini.py +59 -32
  283. agno/tools/models/groq.py +30 -23
  284. agno/tools/models/nebius.py +28 -12
  285. agno/tools/models_labs.py +40 -16
  286. agno/tools/moviepy_video.py +7 -6
  287. agno/tools/neo4j.py +10 -8
  288. agno/tools/newspaper.py +7 -2
  289. agno/tools/newspaper4k.py +8 -3
  290. agno/tools/openai.py +58 -32
  291. agno/tools/openbb.py +12 -11
  292. agno/tools/opencv.py +63 -47
  293. agno/tools/openweather.py +14 -12
  294. agno/tools/pandas.py +11 -3
  295. agno/tools/postgres.py +4 -12
  296. agno/tools/pubmed.py +4 -1
  297. agno/tools/python.py +9 -22
  298. agno/tools/reasoning.py +35 -27
  299. agno/tools/reddit.py +11 -26
  300. agno/tools/replicate.py +55 -42
  301. agno/tools/resend.py +4 -1
  302. agno/tools/scrapegraph.py +15 -14
  303. agno/tools/searxng.py +10 -23
  304. agno/tools/serpapi.py +6 -3
  305. agno/tools/serper.py +13 -4
  306. agno/tools/shell.py +9 -2
  307. agno/tools/slack.py +12 -11
  308. agno/tools/sleep.py +3 -2
  309. agno/tools/spider.py +24 -4
  310. agno/tools/sql.py +7 -6
  311. agno/tools/tavily.py +6 -4
  312. agno/tools/telegram.py +12 -4
  313. agno/tools/todoist.py +11 -31
  314. agno/tools/toolkit.py +1 -1
  315. agno/tools/trafilatura.py +22 -6
  316. agno/tools/trello.py +9 -22
  317. agno/tools/twilio.py +10 -3
  318. agno/tools/user_control_flow.py +6 -1
  319. agno/tools/valyu.py +34 -5
  320. agno/tools/visualization.py +19 -28
  321. agno/tools/webbrowser.py +4 -3
  322. agno/tools/webex.py +11 -7
  323. agno/tools/website.py +15 -46
  324. agno/tools/webtools.py +12 -4
  325. agno/tools/whatsapp.py +5 -9
  326. agno/tools/wikipedia.py +20 -13
  327. agno/tools/x.py +14 -13
  328. agno/tools/yfinance.py +13 -40
  329. agno/tools/youtube.py +26 -20
  330. agno/tools/zendesk.py +7 -2
  331. agno/tools/zep.py +10 -7
  332. agno/tools/zoom.py +10 -9
  333. agno/utils/common.py +1 -19
  334. agno/utils/events.py +100 -123
  335. agno/utils/gemini.py +32 -2
  336. agno/utils/knowledge.py +29 -0
  337. agno/utils/log.py +54 -4
  338. agno/utils/mcp.py +68 -10
  339. agno/utils/media.py +39 -0
  340. agno/utils/message.py +12 -1
  341. agno/utils/models/aws_claude.py +1 -1
  342. agno/utils/models/claude.py +47 -4
  343. agno/utils/models/cohere.py +1 -1
  344. agno/utils/models/mistral.py +8 -7
  345. agno/utils/models/schema_utils.py +3 -3
  346. agno/utils/models/watsonx.py +1 -1
  347. agno/utils/openai.py +1 -1
  348. agno/utils/pprint.py +33 -32
  349. agno/utils/print_response/agent.py +779 -0
  350. agno/utils/print_response/team.py +1669 -0
  351. agno/utils/print_response/workflow.py +1451 -0
  352. agno/utils/prompts.py +14 -14
  353. agno/utils/reasoning.py +87 -0
  354. agno/utils/response.py +42 -42
  355. agno/utils/streamlit.py +481 -0
  356. agno/utils/string.py +8 -22
  357. agno/utils/team.py +50 -0
  358. agno/utils/timer.py +2 -2
  359. agno/vectordb/base.py +33 -21
  360. agno/vectordb/cassandra/cassandra.py +287 -23
  361. agno/vectordb/chroma/chromadb.py +482 -59
  362. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  363. agno/vectordb/couchbase/couchbase.py +309 -29
  364. agno/vectordb/lancedb/lance_db.py +360 -21
  365. agno/vectordb/langchaindb/__init__.py +5 -0
  366. agno/vectordb/langchaindb/langchaindb.py +145 -0
  367. agno/vectordb/lightrag/__init__.py +5 -0
  368. agno/vectordb/lightrag/lightrag.py +374 -0
  369. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  370. agno/vectordb/milvus/milvus.py +242 -32
  371. agno/vectordb/mongodb/mongodb.py +200 -24
  372. agno/vectordb/pgvector/pgvector.py +319 -37
  373. agno/vectordb/pineconedb/pineconedb.py +221 -27
  374. agno/vectordb/qdrant/qdrant.py +334 -14
  375. agno/vectordb/singlestore/singlestore.py +286 -29
  376. agno/vectordb/surrealdb/surrealdb.py +187 -7
  377. agno/vectordb/upstashdb/upstashdb.py +342 -26
  378. agno/vectordb/weaviate/weaviate.py +227 -165
  379. agno/workflow/__init__.py +17 -13
  380. agno/workflow/{v2/condition.py → condition.py} +135 -32
  381. agno/workflow/{v2/loop.py → loop.py} +115 -28
  382. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  383. agno/workflow/{v2/router.py → router.py} +133 -32
  384. agno/workflow/{v2/step.py → step.py} +207 -49
  385. agno/workflow/{v2/steps.py → steps.py} +147 -66
  386. agno/workflow/types.py +482 -0
  387. agno/workflow/workflow.py +2410 -696
  388. agno-2.0.0.dist-info/METADATA +494 -0
  389. agno-2.0.0.dist-info/RECORD +515 -0
  390. agno-2.0.0.dist-info/licenses/LICENSE +201 -0
  391. agno/agent/metrics.py +0 -107
  392. agno/api/app.py +0 -35
  393. agno/api/playground.py +0 -92
  394. agno/api/schemas/app.py +0 -12
  395. agno/api/schemas/playground.py +0 -22
  396. agno/api/schemas/user.py +0 -35
  397. agno/api/schemas/workspace.py +0 -46
  398. agno/api/user.py +0 -160
  399. agno/api/workflows.py +0 -33
  400. agno/api/workspace.py +0 -175
  401. agno/app/agui/__init__.py +0 -3
  402. agno/app/agui/app.py +0 -17
  403. agno/app/agui/sync_router.py +0 -120
  404. agno/app/base.py +0 -186
  405. agno/app/discord/__init__.py +0 -3
  406. agno/app/fastapi/__init__.py +0 -3
  407. agno/app/fastapi/app.py +0 -107
  408. agno/app/fastapi/async_router.py +0 -457
  409. agno/app/fastapi/sync_router.py +0 -448
  410. agno/app/playground/app.py +0 -228
  411. agno/app/playground/async_router.py +0 -1050
  412. agno/app/playground/deploy.py +0 -249
  413. agno/app/playground/operator.py +0 -183
  414. agno/app/playground/schemas.py +0 -220
  415. agno/app/playground/serve.py +0 -55
  416. agno/app/playground/sync_router.py +0 -1042
  417. agno/app/playground/utils.py +0 -46
  418. agno/app/settings.py +0 -15
  419. agno/app/slack/__init__.py +0 -3
  420. agno/app/slack/app.py +0 -19
  421. agno/app/slack/sync_router.py +0 -92
  422. agno/app/utils.py +0 -54
  423. agno/app/whatsapp/__init__.py +0 -3
  424. agno/app/whatsapp/app.py +0 -15
  425. agno/app/whatsapp/sync_router.py +0 -197
  426. agno/cli/auth_server.py +0 -249
  427. agno/cli/config.py +0 -274
  428. agno/cli/console.py +0 -88
  429. agno/cli/credentials.py +0 -23
  430. agno/cli/entrypoint.py +0 -571
  431. agno/cli/operator.py +0 -357
  432. agno/cli/settings.py +0 -96
  433. agno/cli/ws/ws_cli.py +0 -817
  434. agno/constants.py +0 -13
  435. agno/document/__init__.py +0 -5
  436. agno/document/chunking/semantic.py +0 -45
  437. agno/document/chunking/strategy.py +0 -31
  438. agno/document/reader/__init__.py +0 -5
  439. agno/document/reader/base.py +0 -47
  440. agno/document/reader/docx_reader.py +0 -60
  441. agno/document/reader/gcs/pdf_reader.py +0 -44
  442. agno/document/reader/s3/pdf_reader.py +0 -59
  443. agno/document/reader/s3/text_reader.py +0 -63
  444. agno/document/reader/url_reader.py +0 -59
  445. agno/document/reader/youtube_reader.py +0 -58
  446. agno/embedder/__init__.py +0 -5
  447. agno/embedder/langdb.py +0 -80
  448. agno/embedder/mistral.py +0 -82
  449. agno/embedder/openai.py +0 -78
  450. agno/file/__init__.py +0 -5
  451. agno/file/file.py +0 -16
  452. agno/file/local/csv.py +0 -32
  453. agno/file/local/txt.py +0 -19
  454. agno/infra/app.py +0 -240
  455. agno/infra/base.py +0 -144
  456. agno/infra/context.py +0 -20
  457. agno/infra/db_app.py +0 -52
  458. agno/infra/resource.py +0 -205
  459. agno/infra/resources.py +0 -55
  460. agno/knowledge/agent.py +0 -702
  461. agno/knowledge/arxiv.py +0 -33
  462. agno/knowledge/combined.py +0 -36
  463. agno/knowledge/csv.py +0 -144
  464. agno/knowledge/csv_url.py +0 -124
  465. agno/knowledge/document.py +0 -223
  466. agno/knowledge/docx.py +0 -137
  467. agno/knowledge/firecrawl.py +0 -34
  468. agno/knowledge/gcs/__init__.py +0 -0
  469. agno/knowledge/gcs/base.py +0 -39
  470. agno/knowledge/gcs/pdf.py +0 -125
  471. agno/knowledge/json.py +0 -137
  472. agno/knowledge/langchain.py +0 -71
  473. agno/knowledge/light_rag.py +0 -273
  474. agno/knowledge/llamaindex.py +0 -66
  475. agno/knowledge/markdown.py +0 -154
  476. agno/knowledge/pdf.py +0 -164
  477. agno/knowledge/pdf_bytes.py +0 -42
  478. agno/knowledge/pdf_url.py +0 -148
  479. agno/knowledge/s3/__init__.py +0 -0
  480. agno/knowledge/s3/base.py +0 -64
  481. agno/knowledge/s3/pdf.py +0 -33
  482. agno/knowledge/s3/text.py +0 -34
  483. agno/knowledge/text.py +0 -141
  484. agno/knowledge/url.py +0 -46
  485. agno/knowledge/website.py +0 -179
  486. agno/knowledge/wikipedia.py +0 -32
  487. agno/knowledge/youtube.py +0 -35
  488. agno/memory/agent.py +0 -423
  489. agno/memory/classifier.py +0 -104
  490. agno/memory/db/__init__.py +0 -5
  491. agno/memory/db/base.py +0 -42
  492. agno/memory/db/mongodb.py +0 -189
  493. agno/memory/db/postgres.py +0 -203
  494. agno/memory/db/sqlite.py +0 -193
  495. agno/memory/memory.py +0 -22
  496. agno/memory/row.py +0 -36
  497. agno/memory/summarizer.py +0 -201
  498. agno/memory/summary.py +0 -19
  499. agno/memory/team.py +0 -415
  500. agno/memory/v2/__init__.py +0 -2
  501. agno/memory/v2/db/__init__.py +0 -1
  502. agno/memory/v2/db/base.py +0 -42
  503. agno/memory/v2/db/firestore.py +0 -339
  504. agno/memory/v2/db/mongodb.py +0 -196
  505. agno/memory/v2/db/postgres.py +0 -214
  506. agno/memory/v2/db/redis.py +0 -187
  507. agno/memory/v2/db/schema.py +0 -54
  508. agno/memory/v2/db/sqlite.py +0 -209
  509. agno/memory/v2/manager.py +0 -437
  510. agno/memory/v2/memory.py +0 -1097
  511. agno/memory/v2/schema.py +0 -55
  512. agno/memory/v2/summarizer.py +0 -215
  513. agno/memory/workflow.py +0 -38
  514. agno/models/ollama/tools.py +0 -430
  515. agno/models/qwen/__init__.py +0 -5
  516. agno/playground/__init__.py +0 -10
  517. agno/playground/deploy.py +0 -3
  518. agno/playground/playground.py +0 -3
  519. agno/playground/serve.py +0 -3
  520. agno/playground/settings.py +0 -3
  521. agno/reranker/__init__.py +0 -0
  522. agno/run/response.py +0 -467
  523. agno/run/v2/__init__.py +0 -0
  524. agno/run/v2/workflow.py +0 -567
  525. agno/storage/__init__.py +0 -0
  526. agno/storage/agent/__init__.py +0 -0
  527. agno/storage/agent/dynamodb.py +0 -1
  528. agno/storage/agent/json.py +0 -1
  529. agno/storage/agent/mongodb.py +0 -1
  530. agno/storage/agent/postgres.py +0 -1
  531. agno/storage/agent/singlestore.py +0 -1
  532. agno/storage/agent/sqlite.py +0 -1
  533. agno/storage/agent/yaml.py +0 -1
  534. agno/storage/base.py +0 -60
  535. agno/storage/dynamodb.py +0 -673
  536. agno/storage/firestore.py +0 -297
  537. agno/storage/gcs_json.py +0 -261
  538. agno/storage/in_memory.py +0 -234
  539. agno/storage/json.py +0 -237
  540. agno/storage/mongodb.py +0 -328
  541. agno/storage/mysql.py +0 -685
  542. agno/storage/postgres.py +0 -682
  543. agno/storage/redis.py +0 -336
  544. agno/storage/session/__init__.py +0 -16
  545. agno/storage/session/agent.py +0 -64
  546. agno/storage/session/team.py +0 -63
  547. agno/storage/session/v2/__init__.py +0 -5
  548. agno/storage/session/workflow.py +0 -61
  549. agno/storage/singlestore.py +0 -606
  550. agno/storage/sqlite.py +0 -646
  551. agno/storage/workflow/__init__.py +0 -0
  552. agno/storage/workflow/mongodb.py +0 -1
  553. agno/storage/workflow/postgres.py +0 -1
  554. agno/storage/workflow/sqlite.py +0 -1
  555. agno/storage/yaml.py +0 -241
  556. agno/tools/thinking.py +0 -73
  557. agno/utils/defaults.py +0 -57
  558. agno/utils/filesystem.py +0 -39
  559. agno/utils/git.py +0 -52
  560. agno/utils/json_io.py +0 -30
  561. agno/utils/load_env.py +0 -19
  562. agno/utils/py_io.py +0 -19
  563. agno/utils/pyproject.py +0 -18
  564. agno/utils/resource_filter.py +0 -31
  565. agno/workflow/v2/__init__.py +0 -21
  566. agno/workflow/v2/types.py +0 -357
  567. agno/workflow/v2/workflow.py +0 -3312
  568. agno/workspace/__init__.py +0 -0
  569. agno/workspace/config.py +0 -325
  570. agno/workspace/enums.py +0 -6
  571. agno/workspace/helpers.py +0 -52
  572. agno/workspace/operator.py +0 -757
  573. agno/workspace/settings.py +0 -158
  574. agno-1.8.1.dist-info/METADATA +0 -982
  575. agno-1.8.1.dist-info/RECORD +0 -566
  576. agno-1.8.1.dist-info/entry_points.txt +0 -3
  577. agno-1.8.1.dist-info/licenses/LICENSE +0 -375
  578. /agno/{app → db/migrations}/__init__.py +0 -0
  579. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  580. /agno/{cli → integrations}/__init__.py +0 -0
  581. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  582. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  583. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  584. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  585. /agno/{app → os/interfaces}/slack/security.py +0 -0
  586. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  587. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  588. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  589. {agno-1.8.1.dist-info → agno-2.0.0.dist-info}/WHEEL +0 -0
  590. {agno-1.8.1.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