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
@@ -1,1053 +0,0 @@
1
- import json
2
- from io import BytesIO
3
- from typing import Any, AsyncGenerator, Dict, List, Optional, cast
4
- from uuid import uuid4
5
-
6
- from fastapi import APIRouter, File, Form, HTTPException, Query, UploadFile
7
- from fastapi.responses import JSONResponse, StreamingResponse
8
-
9
- from agno.agent.agent import Agent, RunResponse
10
- from agno.app.playground.operator import (
11
- format_tools,
12
- get_agent_by_id,
13
- get_session_title,
14
- get_session_title_from_team_session,
15
- get_session_title_from_workflow_session,
16
- get_team_by_id,
17
- get_workflow_by_id,
18
- )
19
- from agno.app.playground.schemas import (
20
- AgentGetResponse,
21
- AgentModel,
22
- AgentRenameRequest,
23
- AgentSessionsResponse,
24
- MemoryResponse,
25
- TeamGetResponse,
26
- TeamRenameRequest,
27
- TeamSessionResponse,
28
- WorkflowGetResponse,
29
- WorkflowRenameRequest,
30
- WorkflowRunRequest,
31
- WorkflowSessionResponse,
32
- WorkflowsGetResponse,
33
- )
34
- from agno.app.playground.utils import process_audio, process_document, process_image, process_video
35
- from agno.media import Audio, Image, Video
36
- from agno.media import File as FileMedia
37
- from agno.memory.agent import AgentMemory
38
- from agno.memory.v2 import Memory
39
- from agno.run.response import RunResponseErrorEvent, RunResponseEvent
40
- from agno.run.team import RunResponseErrorEvent as TeamRunResponseErrorEvent
41
- from agno.run.v2.workflow import WorkflowErrorEvent
42
- from agno.storage.session.agent import AgentSession
43
- from agno.storage.session.team import TeamSession
44
- from agno.storage.session.workflow import WorkflowSession
45
- from agno.team.team import Team
46
- from agno.utils.log import logger
47
- from agno.workflow.v2.workflow import Workflow as WorkflowV2
48
- from agno.workflow.workflow import Workflow
49
-
50
-
51
- async def chat_response_streamer(
52
- agent: Agent,
53
- message: str,
54
- session_id: Optional[str] = None,
55
- user_id: Optional[str] = None,
56
- images: Optional[List[Image]] = None,
57
- audio: Optional[List[Audio]] = None,
58
- videos: Optional[List[Video]] = None,
59
- files: Optional[List[FileMedia]] = None,
60
- ) -> AsyncGenerator:
61
- try:
62
- run_response = await agent.arun(
63
- message,
64
- session_id=session_id,
65
- user_id=user_id,
66
- images=images,
67
- audio=audio,
68
- videos=videos,
69
- files=files,
70
- stream=True,
71
- stream_intermediate_steps=True,
72
- )
73
- async for run_response_chunk in run_response:
74
- yield run_response_chunk.to_json()
75
- except Exception as e:
76
- import traceback
77
-
78
- traceback.print_exc(limit=3)
79
- error_response = RunResponseErrorEvent(
80
- content=str(e),
81
- )
82
- yield error_response.to_json()
83
- return
84
-
85
-
86
- async def agent_acontinue_run_streamer(
87
- agent: Agent,
88
- run_id: Optional[str] = None,
89
- updated_tools: Optional[List] = None,
90
- session_id: Optional[str] = None,
91
- user_id: Optional[str] = None,
92
- ) -> AsyncGenerator:
93
- try:
94
- continue_response = await agent.acontinue_run(
95
- run_id=run_id,
96
- updated_tools=updated_tools,
97
- session_id=session_id,
98
- user_id=user_id,
99
- stream=True,
100
- stream_intermediate_steps=True,
101
- )
102
- async for run_response_chunk in continue_response:
103
- run_response_chunk = cast(RunResponseEvent, run_response_chunk)
104
- yield run_response_chunk.to_json()
105
- except Exception as e:
106
- import traceback
107
-
108
- traceback.print_exc(limit=3)
109
- error_response = RunResponseErrorEvent(
110
- content=str(e),
111
- )
112
- yield error_response.to_json()
113
- return
114
-
115
-
116
- async def team_chat_response_streamer(
117
- team: Team,
118
- message: str,
119
- session_id: Optional[str] = None,
120
- user_id: Optional[str] = None,
121
- images: Optional[List[Image]] = None,
122
- audio: Optional[List[Audio]] = None,
123
- videos: Optional[List[Video]] = None,
124
- files: Optional[List[FileMedia]] = None,
125
- ) -> AsyncGenerator:
126
- try:
127
- run_response = await team.arun(
128
- message,
129
- session_id=session_id,
130
- user_id=user_id,
131
- images=images,
132
- audio=audio,
133
- videos=videos,
134
- files=files,
135
- stream=True,
136
- stream_intermediate_steps=True,
137
- )
138
- async for run_response_chunk in run_response:
139
- yield run_response_chunk.to_json()
140
- except Exception as e:
141
- import traceback
142
-
143
- traceback.print_exc()
144
- error_response = TeamRunResponseErrorEvent(
145
- content=str(e),
146
- )
147
- yield error_response.to_json()
148
- return
149
-
150
-
151
- async def workflow_response_streamer(
152
- workflow: WorkflowV2,
153
- body: WorkflowRunRequest,
154
- ) -> AsyncGenerator:
155
- try:
156
- run_response = await workflow.arun(
157
- **body.input,
158
- user_id=body.user_id,
159
- session_id=body.session_id or str(uuid4()),
160
- stream=True,
161
- stream_intermediate_steps=True,
162
- )
163
- async for run_response_chunk in run_response:
164
- yield run_response_chunk.to_json()
165
- except Exception as e:
166
- import traceback
167
-
168
- traceback.print_exc(limit=3)
169
- error_response = WorkflowErrorEvent(
170
- error=str(e),
171
- )
172
- yield error_response.to_json()
173
- return
174
-
175
-
176
- def get_async_playground_router(
177
- agents: Optional[List[Agent]] = None,
178
- workflows: Optional[List[Workflow]] = None,
179
- teams: Optional[List[Team]] = None,
180
- active_app_id: Optional[str] = None,
181
- ) -> APIRouter:
182
- playground_router = APIRouter(prefix="/playground", tags=["Playground"])
183
-
184
- if agents is None and workflows is None and teams is None:
185
- raise ValueError("Either agents, teams or workflows must be provided.")
186
-
187
- @playground_router.get("/status")
188
- async def playground_status(app_id: Optional[str] = None):
189
- if app_id is None:
190
- return {"playground": "available"}
191
- else:
192
- if active_app_id == app_id:
193
- return {"playground": "available"}
194
- else:
195
- raise HTTPException(status_code=404, detail="Playground not available")
196
-
197
- @playground_router.get("/agents", response_model=List[AgentGetResponse])
198
- async def get_agents():
199
- agent_list: List[AgentGetResponse] = []
200
- if agents is None:
201
- return agent_list
202
-
203
- for agent in agents:
204
- agent_tools = agent.get_tools(session_id=str(uuid4()), async_mode=True)
205
- formatted_tools = format_tools(agent_tools)
206
-
207
- name = agent.model.name or agent.model.__class__.__name__ if agent.model else None
208
- provider = agent.model.provider or agent.model.__class__.__name__ if agent.model else ""
209
- model_id = agent.model.id if agent.model else None
210
-
211
- # Create an agent_id if its not set on the agent
212
- if agent.agent_id is None:
213
- agent.set_agent_id()
214
-
215
- if provider and model_id:
216
- provider = f"{provider} {model_id}"
217
- elif name and model_id:
218
- provider = f"{name} {model_id}"
219
- elif model_id:
220
- provider = model_id
221
- else:
222
- provider = ""
223
-
224
- if agent.memory:
225
- memory_dict: Optional[Dict[str, Any]] = {}
226
- if isinstance(agent.memory, AgentMemory) and agent.memory.db:
227
- memory_dict = {"name": agent.memory.db.__class__.__name__}
228
- elif isinstance(agent.memory, Memory) and agent.memory.db:
229
- memory_dict = {"name": "Memory"}
230
- if agent.memory.model is not None:
231
- memory_dict["model"] = AgentModel(
232
- name=agent.memory.model.name,
233
- model=agent.memory.model.id,
234
- provider=agent.memory.model.provider,
235
- )
236
- else:
237
- memory_dict["model"] = AgentModel(
238
- name=name,
239
- model=model_id,
240
- provider=provider,
241
- )
242
-
243
- if agent.memory.db is not None:
244
- memory_dict["db"] = agent.memory.db.__dict__() # type: ignore
245
-
246
- else:
247
- memory_dict = None
248
- else:
249
- memory_dict = None
250
-
251
- agent_list.append(
252
- AgentGetResponse(
253
- agent_id=agent.agent_id,
254
- name=agent.name,
255
- model=AgentModel(
256
- name=name,
257
- model=model_id,
258
- provider=provider,
259
- ),
260
- add_context=agent.add_context,
261
- tools=formatted_tools,
262
- memory=memory_dict,
263
- storage={"name": agent.storage.__class__.__name__} if agent.storage else None,
264
- knowledge={"name": agent.knowledge.__class__.__name__} if agent.knowledge else None,
265
- description=agent.description,
266
- instructions=agent.instructions,
267
- )
268
- )
269
-
270
- return agent_list
271
-
272
- @playground_router.post("/agents/{agent_id}/runs")
273
- async def create_agent_run(
274
- agent_id: str,
275
- message: str = Form(...),
276
- stream: bool = Form(True),
277
- monitor: bool = Form(False),
278
- session_id: Optional[str] = Form(None),
279
- user_id: Optional[str] = Form(None),
280
- files: Optional[List[UploadFile]] = File(None),
281
- ):
282
- logger.debug(f"AgentRunRequest: {message} {session_id} {user_id} {agent_id}")
283
- agent = get_agent_by_id(agent_id, agents)
284
- if agent is None:
285
- raise HTTPException(status_code=404, detail="Agent not found")
286
-
287
- if session_id is not None and session_id != "":
288
- logger.debug(f"Continuing session: {session_id}")
289
- else:
290
- logger.debug("Creating new session")
291
- session_id = str(uuid4())
292
-
293
- if monitor:
294
- agent.monitoring = True
295
- else:
296
- agent.monitoring = False
297
-
298
- base64_images: List[Image] = []
299
- base64_audios: List[Audio] = []
300
- base64_videos: List[Video] = []
301
- input_files: List[FileMedia] = []
302
-
303
- if files:
304
- for file in files:
305
- logger.info(f"Processing file: {file.content_type}")
306
- if file.content_type in ["image/png", "image/jpeg", "image/jpg", "image/webp"]:
307
- try:
308
- base64_image = process_image(file)
309
- base64_images.append(base64_image)
310
- except Exception as e:
311
- logger.error(f"Error processing image {file.filename}: {e}")
312
- continue
313
- elif file.content_type in ["audio/wav", "audio/mp3", "audio/mpeg"]:
314
- try:
315
- base64_audio = process_audio(file)
316
- base64_audios.append(base64_audio)
317
- except Exception as e:
318
- logger.error(f"Error processing audio {file.filename}: {e}")
319
- continue
320
- elif file.content_type in [
321
- "video/x-flv",
322
- "video/quicktime",
323
- "video/mpeg",
324
- "video/mpegs",
325
- "video/mpgs",
326
- "video/mpg",
327
- "video/mpg",
328
- "video/mp4",
329
- "video/webm",
330
- "video/wmv",
331
- "video/3gpp",
332
- ]:
333
- try:
334
- base64_video = process_video(file)
335
- base64_videos.append(base64_video)
336
- except Exception as e:
337
- logger.error(f"Error processing video {file.filename}: {e}")
338
- continue
339
- else:
340
- # Process document files
341
- if file.content_type == "application/pdf":
342
- from agno.document.reader.pdf_reader import PDFReader
343
-
344
- contents = await file.read()
345
-
346
- # If agent has knowledge base, load the document into it
347
- if agent.knowledge is not None:
348
- pdf_file = BytesIO(contents)
349
- pdf_file.name = file.filename
350
- file_content = PDFReader().read(pdf_file)
351
- agent.knowledge.load_documents(file_content)
352
- else:
353
- # If no knowledge base, treat as direct file input (similar to cookbook examples)
354
- input_files.append(FileMedia(content=contents))
355
-
356
- elif file.content_type == "text/csv":
357
- from agno.document.reader.csv_reader import CSVReader
358
-
359
- contents = await file.read()
360
-
361
- # If agent has knowledge base, load the document into it
362
- if agent.knowledge is not None:
363
- csv_file = BytesIO(contents)
364
- csv_file.name = file.filename
365
- file_content = CSVReader().read(csv_file)
366
- agent.knowledge.load_documents(file_content)
367
- else:
368
- # If no knowledge base, treat as direct file input
369
- input_files.append(FileMedia(content=contents))
370
-
371
- elif file.content_type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
372
- from agno.document.reader.docx_reader import DocxReader
373
-
374
- contents = await file.read()
375
-
376
- # If agent has knowledge base, load the document into it
377
- if agent.knowledge is not None:
378
- docx_file = BytesIO(contents)
379
- docx_file.name = file.filename
380
- file_content = DocxReader().read(docx_file)
381
- agent.knowledge.load_documents(file_content)
382
- else:
383
- # If no knowledge base, treat as direct file input
384
- input_files.append(FileMedia(content=contents))
385
-
386
- elif file.content_type == "text/plain":
387
- from agno.document.reader.text_reader import TextReader
388
-
389
- contents = await file.read()
390
-
391
- # If agent has knowledge base, load the document into it
392
- if agent.knowledge is not None:
393
- text_file = BytesIO(contents)
394
- text_file.name = file.filename
395
- file_content = TextReader().read(text_file)
396
- agent.knowledge.load_documents(file_content)
397
- else:
398
- # If no knowledge base, treat as direct file input
399
- input_files.append(FileMedia(content=contents))
400
-
401
- elif file.content_type == "application/json":
402
- from agno.document.reader.json_reader import JSONReader
403
-
404
- contents = await file.read()
405
-
406
- # If agent has knowledge base, load the document into it
407
- if agent.knowledge is not None:
408
- json_file = BytesIO(contents)
409
- json_file.name = file.filename
410
- file_content = JSONReader().read(json_file)
411
- agent.knowledge.load_documents(file_content)
412
- else:
413
- # If no knowledge base, treat as direct file input
414
- input_files.append(FileMedia(content=contents))
415
- else:
416
- raise HTTPException(status_code=400, detail="Unsupported file type")
417
-
418
- if stream:
419
- return StreamingResponse(
420
- chat_response_streamer(
421
- agent,
422
- message,
423
- session_id=session_id,
424
- user_id=user_id,
425
- images=base64_images if base64_images else None,
426
- audio=base64_audios if base64_audios else None,
427
- videos=base64_videos if base64_videos else None,
428
- files=input_files if input_files else None,
429
- ),
430
- media_type="text/event-stream",
431
- )
432
- else:
433
- run_response = cast(
434
- RunResponse,
435
- await agent.arun(
436
- message=message,
437
- session_id=session_id,
438
- user_id=user_id,
439
- images=base64_images if base64_images else None,
440
- audio=base64_audios if base64_audios else None,
441
- videos=base64_videos if base64_videos else None,
442
- files=input_files if input_files else None,
443
- stream=False,
444
- ),
445
- )
446
- return run_response.to_dict()
447
-
448
- @playground_router.post("/agents/{agent_id}/runs/{run_id}/continue")
449
- async def continue_agent_run(
450
- agent_id: str,
451
- run_id: str,
452
- tools: str = Form(...), # JSON string of tools
453
- session_id: Optional[str] = Form(None),
454
- user_id: Optional[str] = Form(None),
455
- stream: bool = Form(True),
456
- ):
457
- # Parse the JSON string manually
458
- try:
459
- tools_data = json.loads(tools) if tools else None
460
- except json.JSONDecodeError:
461
- raise HTTPException(status_code=400, detail="Invalid JSON in tools field")
462
-
463
- logger.debug(
464
- f"AgentContinueRunRequest: run_id={run_id} session_id={session_id} user_id={user_id} agent_id={agent_id}"
465
- )
466
- agent = get_agent_by_id(agent_id, agents)
467
- if agent is None:
468
- raise HTTPException(status_code=404, detail="Agent not found")
469
-
470
- if session_id is None or session_id == "":
471
- logger.warning(
472
- "Continuing run without session_id. This might lead to unexpected behavior if session context is important."
473
- )
474
- else:
475
- logger.debug(f"Continuing run within session: {session_id}")
476
-
477
- # Convert tools dict to ToolExecution objects if provided
478
- updated_tools = None
479
- if tools_data:
480
- try:
481
- from agno.models.response import ToolExecution
482
-
483
- updated_tools = [ToolExecution.from_dict(tool) for tool in tools_data]
484
- except Exception as e:
485
- raise HTTPException(status_code=400, detail=f"Invalid structure or content for tools: {str(e)}")
486
-
487
- if stream:
488
- return StreamingResponse(
489
- agent_acontinue_run_streamer(
490
- agent,
491
- run_id=run_id, # run_id from path
492
- updated_tools=updated_tools,
493
- session_id=session_id,
494
- user_id=user_id,
495
- ),
496
- media_type="text/event-stream",
497
- )
498
- else:
499
- run_response_obj = cast(
500
- RunResponse,
501
- await agent.acontinue_run(
502
- run_id=run_id, # run_id from path
503
- updated_tools=updated_tools,
504
- session_id=session_id,
505
- user_id=user_id,
506
- stream=False,
507
- ),
508
- )
509
- return run_response_obj.to_dict()
510
-
511
- @playground_router.get("/agents/{agent_id}/sessions")
512
- async def get_all_agent_sessions(agent_id: str, user_id: Optional[str] = Query(None, min_length=1)):
513
- logger.debug(f"AgentSessionsRequest: {agent_id} {user_id}")
514
- agent = get_agent_by_id(agent_id, agents)
515
- if agent is None:
516
- return JSONResponse(status_code=404, content="Agent not found.")
517
-
518
- if agent.storage is None:
519
- return JSONResponse(status_code=404, content="Agent does not have storage enabled.")
520
-
521
- agent_sessions: List[AgentSessionsResponse] = []
522
- all_agent_sessions: List[AgentSession] = agent.storage.get_all_sessions(user_id=user_id, entity_id=agent_id) # type: ignore
523
- for session in all_agent_sessions:
524
- title = get_session_title(session)
525
- agent_sessions.append(
526
- AgentSessionsResponse(
527
- title=title,
528
- session_id=session.session_id,
529
- session_name=session.session_data.get("session_name") if session.session_data else None,
530
- created_at=session.created_at,
531
- updated_at=session.updated_at,
532
- )
533
- )
534
- return agent_sessions
535
-
536
- @playground_router.get("/agents/{agent_id}/sessions/{session_id}")
537
- async def get_agent_session(agent_id: str, session_id: str, user_id: Optional[str] = Query(None, min_length=1)):
538
- logger.debug(f"AgentSessionsRequest: {agent_id} {user_id} {session_id}")
539
- agent = get_agent_by_id(agent_id, agents)
540
- if agent is None:
541
- raise HTTPException(status_code=404, detail="Agent not found")
542
-
543
- if agent.storage is None:
544
- return JSONResponse(status_code=404, content="Agent does not have storage enabled.")
545
-
546
- agent_session: Optional[AgentSession] = agent.storage.read(session_id, user_id) # type: ignore
547
- if agent_session is None:
548
- return JSONResponse(status_code=404, content="Session not found.")
549
-
550
- agent_session_dict = agent_session.to_dict()
551
- if agent_session.memory is not None:
552
- runs = agent_session.memory.get("runs")
553
- if runs is not None:
554
- first_run = runs[0]
555
- # This is how we know it is a RunResponse or RunPaused
556
- if "content" in first_run or first_run.get("is_paused", False) or first_run.get("event") == "RunPaused":
557
- agent_session_dict["runs"] = []
558
-
559
- for run in runs:
560
- first_user_message = None
561
- for msg in run.get("messages", []):
562
- if msg.get("role") == "user" and msg.get("from_history", False) is False:
563
- first_user_message = msg
564
- break
565
- # Remove the memory from the response
566
- run.pop("memory", None)
567
- agent_session_dict["runs"].append(
568
- {
569
- "message": first_user_message,
570
- "response": run,
571
- }
572
- )
573
- return agent_session_dict
574
-
575
- @playground_router.post("/agents/{agent_id}/sessions/{session_id}/rename")
576
- async def rename_agent_session(agent_id: str, session_id: str, body: AgentRenameRequest):
577
- agent = get_agent_by_id(agent_id, agents)
578
- if agent is None:
579
- return JSONResponse(status_code=404, content=f"couldn't find agent with {agent_id}")
580
-
581
- if agent.storage is None:
582
- return JSONResponse(status_code=404, content="Agent does not have storage enabled.")
583
-
584
- all_agent_sessions: List[AgentSession] = agent.storage.get_all_sessions(user_id=body.user_id) # type: ignore
585
- for session in all_agent_sessions:
586
- if session.session_id == session_id:
587
- agent.rename_session(body.name, session_id=session_id)
588
- return JSONResponse(content={"message": f"successfully renamed session {session.session_id}"})
589
-
590
- return JSONResponse(status_code=404, content="Session not found.")
591
-
592
- @playground_router.delete("/agents/{agent_id}/sessions/{session_id}")
593
- async def delete_agent_session(agent_id: str, session_id: str, user_id: Optional[str] = Query(None, min_length=1)):
594
- agent = get_agent_by_id(agent_id, agents)
595
- if agent is None:
596
- return JSONResponse(status_code=404, content="Agent not found.")
597
-
598
- if agent.storage is None:
599
- return JSONResponse(status_code=404, content="Agent does not have storage enabled.")
600
-
601
- all_agent_sessions: List[AgentSession] = agent.storage.get_all_sessions(user_id=user_id, entity_id=agent_id) # type: ignore
602
- for session in all_agent_sessions:
603
- if session.session_id == session_id:
604
- agent.delete_session(session_id)
605
- return JSONResponse(content={"message": f"successfully deleted session {session_id}"})
606
-
607
- return JSONResponse(status_code=404, content="Session not found.")
608
-
609
- @playground_router.get("/agents/{agent_id}/memories")
610
- async def get_agent_memories(agent_id: str, user_id: str = Query(..., min_length=1)):
611
- agent = get_agent_by_id(agent_id, agents)
612
- if agent is None:
613
- return JSONResponse(status_code=404, content="Agent not found.")
614
-
615
- if agent.memory is None:
616
- return JSONResponse(status_code=404, content="Agent does not have memory enabled.")
617
-
618
- if isinstance(agent.memory, Memory):
619
- memories = agent.memory.get_user_memories(user_id=user_id)
620
- return [
621
- MemoryResponse(memory=memory.memory, topics=memory.topics, last_updated=memory.last_updated)
622
- for memory in memories
623
- ]
624
- else:
625
- return []
626
-
627
- @playground_router.get("/workflows", response_model=List[WorkflowsGetResponse])
628
- async def get_workflows():
629
- if workflows is None:
630
- return []
631
-
632
- return [
633
- WorkflowsGetResponse(
634
- workflow_id=str(workflow.workflow_id),
635
- name=workflow.name,
636
- description=workflow.description,
637
- )
638
- for workflow in workflows
639
- ]
640
-
641
- @playground_router.get("/workflows/{workflow_id}", response_model=WorkflowGetResponse)
642
- async def get_workflow(workflow_id: str):
643
- workflow = get_workflow_by_id(workflow_id, workflows)
644
- if workflow is None:
645
- raise HTTPException(status_code=404, detail="Workflow not found")
646
-
647
- if isinstance(workflow, Workflow):
648
- return WorkflowGetResponse(
649
- workflow_id=workflow.workflow_id,
650
- name=workflow.name,
651
- description=workflow.description,
652
- parameters=workflow._run_parameters or {},
653
- storage=workflow.storage.__class__.__name__ if workflow.storage else None,
654
- )
655
- else:
656
- return WorkflowGetResponse(
657
- workflow_id=workflow.workflow_id,
658
- name=workflow.name,
659
- description=workflow.description,
660
- parameters=workflow.run_parameters,
661
- storage=workflow.storage.__class__.__name__ if workflow.storage else None,
662
- )
663
-
664
- @playground_router.post("/workflows/{workflow_id}/runs")
665
- async def create_workflow_run(workflow_id: str, body: WorkflowRunRequest):
666
- # Retrieve the workflow by ID
667
- workflow = get_workflow_by_id(workflow_id, workflows)
668
- if workflow is None:
669
- raise HTTPException(status_code=404, detail="Workflow not found")
670
-
671
- if body.session_id is not None:
672
- logger.debug(f"Continuing session: {body.session_id}")
673
- else:
674
- logger.debug("Creating new session")
675
-
676
- # Create a new instance of this workflow
677
- if isinstance(workflow, Workflow):
678
- new_workflow_instance = workflow.deep_copy(
679
- update={"workflow_id": workflow_id, "session_id": body.session_id}
680
- )
681
- new_workflow_instance.user_id = body.user_id
682
- new_workflow_instance.session_name = None
683
-
684
- # Return based on the response type
685
- try:
686
- if new_workflow_instance._run_return_type == "RunResponse":
687
- # Return as a normal response
688
- return new_workflow_instance.run(**body.input)
689
- else:
690
- # Return as a streaming response
691
- return StreamingResponse(
692
- (result.to_json() for result in new_workflow_instance.run(**body.input)),
693
- media_type="text/event-stream",
694
- headers={
695
- "Access-Control-Allow-Origin": "*",
696
- "Access-Control-Allow-Methods": "POST, OPTIONS",
697
- "Access-Control-Allow-Headers": "Content-Type, Authorization",
698
- },
699
- )
700
- except Exception as e:
701
- # Handle unexpected runtime errors
702
- raise HTTPException(status_code=500, detail=f"Error running workflow: {str(e)}")
703
- else:
704
- # Return based on the response type
705
- try:
706
- if body.stream:
707
- # Return as a streaming response
708
- return StreamingResponse(
709
- workflow_response_streamer(workflow, body),
710
- media_type="text/event-stream",
711
- headers={
712
- "Access-Control-Allow-Origin": "*",
713
- "Access-Control-Allow-Methods": "POST, OPTIONS",
714
- "Access-Control-Allow-Headers": "Content-Type, Authorization",
715
- },
716
- )
717
- else:
718
- # Return as a normal response
719
- return await workflow.arun(
720
- **body.input, session_id=body.session_id or str(uuid4()), user_id=body.user_id
721
- )
722
- except Exception as e:
723
- # Handle unexpected runtime errors
724
- raise HTTPException(status_code=500, detail=f"Error running workflow: {str(e)}")
725
-
726
- @playground_router.get("/workflows/{workflow_id}/sessions")
727
- async def get_all_workflow_sessions(workflow_id: str, user_id: Optional[str] = Query(None, min_length=1)):
728
- # Retrieve the workflow by ID
729
- workflow = get_workflow_by_id(workflow_id, workflows)
730
- if not workflow:
731
- raise HTTPException(status_code=404, detail="Workflow not found")
732
-
733
- # Ensure storage is enabled for the workflow
734
- if not workflow.storage:
735
- raise HTTPException(status_code=404, detail="Workflow does not have storage enabled")
736
-
737
- # Retrieve all sessions for the given workflow and user
738
- try:
739
- all_workflow_sessions: List[WorkflowSession] = workflow.storage.get_all_sessions(
740
- user_id=user_id, entity_id=workflow_id
741
- ) # type: ignore
742
- except Exception as e:
743
- raise HTTPException(status_code=500, detail=f"Error retrieving sessions: {str(e)}")
744
-
745
- # Return the sessions
746
- workflow_sessions: List[WorkflowSessionResponse] = []
747
- for session in all_workflow_sessions:
748
- title = get_session_title_from_workflow_session(session)
749
- workflow_sessions.append(
750
- {
751
- "title": title,
752
- "session_id": session.session_id,
753
- "session_name": session.session_data.get("session_name") if session.session_data else None,
754
- "created_at": session.created_at,
755
- "updated_at": session.updated_at,
756
- } # type: ignore
757
- )
758
- return workflow_sessions
759
-
760
- @playground_router.get("/workflows/{workflow_id}/sessions/{session_id}")
761
- async def get_workflow_session(
762
- workflow_id: str, session_id: str, user_id: Optional[str] = Query(None, min_length=1)
763
- ):
764
- # Retrieve the workflow by ID
765
- workflow = get_workflow_by_id(workflow_id, workflows)
766
- if not workflow:
767
- raise HTTPException(status_code=404, detail="Workflow not found")
768
-
769
- # Ensure storage is enabled for the workflow
770
- if not workflow.storage:
771
- raise HTTPException(status_code=404, detail="Workflow does not have storage enabled")
772
-
773
- # Retrieve the specific session
774
- try:
775
- workflow_session = workflow.storage.read(session_id, user_id) # type: ignore
776
- except Exception as e:
777
- raise HTTPException(status_code=500, detail=f"Error retrieving session: {str(e)}")
778
-
779
- if not workflow_session:
780
- raise HTTPException(status_code=404, detail="Session not found")
781
-
782
- workflow_session_dict = workflow_session.to_dict()
783
- if "memory" not in workflow_session_dict:
784
- workflow_session_dict["memory"] = {"runs": workflow_session_dict.pop("runs", [])}
785
-
786
- return JSONResponse(content=workflow_session_dict)
787
-
788
- @playground_router.post("/workflows/{workflow_id}/sessions/{session_id}/rename")
789
- async def rename_workflow_session(workflow_id: str, session_id: str, body: WorkflowRenameRequest):
790
- workflow = get_workflow_by_id(workflow_id, workflows)
791
- if workflow is None:
792
- raise HTTPException(status_code=404, detail="Workflow not found")
793
- workflow.session_id = session_id
794
- workflow.rename_session(body.name)
795
- return JSONResponse(content={"message": f"successfully renamed workflow {workflow.name}"})
796
-
797
- @playground_router.delete("/workflows/{workflow_id}/sessions/{session_id}")
798
- async def delete_workflow_session(workflow_id: str, session_id: str):
799
- workflow = get_workflow_by_id(workflow_id, workflows)
800
- if workflow is None:
801
- raise HTTPException(status_code=404, detail="Workflow not found")
802
-
803
- workflow.delete_session(session_id)
804
- return JSONResponse(content={"message": f"successfully deleted workflow {workflow.name}"})
805
-
806
- @playground_router.get("/teams")
807
- async def get_teams():
808
- if teams is None:
809
- return []
810
-
811
- return [TeamGetResponse.from_team(team, async_mode=True) for team in teams]
812
-
813
- @playground_router.get("/teams/{team_id}")
814
- async def get_team(team_id: str):
815
- team = get_team_by_id(team_id, teams)
816
- if team is None:
817
- raise HTTPException(status_code=404, detail="Team not found")
818
-
819
- return TeamGetResponse.from_team(team, async_mode=True)
820
-
821
- @playground_router.post("/teams/{team_id}/runs")
822
- async def create_team_run(
823
- team_id: str,
824
- message: str = Form(...),
825
- stream: bool = Form(True),
826
- monitor: bool = Form(True),
827
- session_id: Optional[str] = Form(None),
828
- user_id: Optional[str] = Form(None),
829
- files: Optional[List[UploadFile]] = File(None),
830
- ):
831
- logger.debug(f"Creating team run: {message} {session_id} {monitor} {user_id} {team_id} {files}")
832
- team = get_team_by_id(team_id, teams)
833
- if team is None:
834
- raise HTTPException(status_code=404, detail="Team not found")
835
-
836
- if session_id is not None and session_id != "":
837
- logger.debug(f"Continuing session: {session_id}")
838
- else:
839
- logger.debug("Creating new session")
840
- session_id = str(uuid4())
841
-
842
- if monitor:
843
- team.monitoring = True
844
- else:
845
- team.monitoring = False
846
-
847
- base64_images: List[Image] = []
848
- base64_audios: List[Audio] = []
849
- base64_videos: List[Video] = []
850
- document_files: List[FileMedia] = []
851
-
852
- if files:
853
- for file in files:
854
- if file.content_type in ["image/png", "image/jpeg", "image/jpg", "image/webp"]:
855
- try:
856
- base64_image = process_image(file)
857
- base64_images.append(base64_image)
858
- except Exception as e:
859
- logger.error(f"Error processing image {file.filename}: {e}")
860
- continue
861
- elif file.content_type in ["audio/wav", "audio/mp3", "audio/mpeg"]:
862
- try:
863
- base64_audio = process_audio(file)
864
- base64_audios.append(base64_audio)
865
- except Exception as e:
866
- logger.error(f"Error processing audio {file.filename}: {e}")
867
- continue
868
- elif file.content_type in [
869
- "video/x-flv",
870
- "video/quicktime",
871
- "video/mpeg",
872
- "video/mpegs",
873
- "video/mpgs",
874
- "video/mpg",
875
- "video/mpg",
876
- "video/mp4",
877
- "video/webm",
878
- "video/wmv",
879
- "video/3gpp",
880
- ]:
881
- try:
882
- base64_video = process_video(file)
883
- base64_videos.append(base64_video)
884
- except Exception as e:
885
- logger.error(f"Error processing video {file.filename}: {e}")
886
- continue
887
- elif file.content_type in [
888
- "application/pdf",
889
- "text/csv",
890
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
891
- "text/plain",
892
- "application/json",
893
- ]:
894
- document_file = process_document(file)
895
- if document_file is not None:
896
- document_files.append(document_file)
897
- else:
898
- raise HTTPException(status_code=400, detail="Unsupported file type")
899
-
900
- if stream:
901
- return StreamingResponse(
902
- team_chat_response_streamer(
903
- team,
904
- message,
905
- session_id=session_id,
906
- user_id=user_id,
907
- images=base64_images if base64_images else None,
908
- audio=base64_audios if base64_audios else None,
909
- videos=base64_videos if base64_videos else None,
910
- files=document_files if document_files else None,
911
- ),
912
- media_type="text/event-stream",
913
- )
914
- else:
915
- run_response = await team.arun(
916
- message=message,
917
- session_id=session_id,
918
- user_id=user_id,
919
- images=base64_images if base64_images else None,
920
- audio=base64_audios if base64_audios else None,
921
- videos=base64_videos if base64_videos else None,
922
- files=document_files if document_files else None,
923
- stream=False,
924
- )
925
- return run_response.to_dict()
926
-
927
- @playground_router.get("/teams/{team_id}/sessions", response_model=List[TeamSessionResponse])
928
- async def get_all_team_sessions(team_id: str, user_id: Optional[str] = Query(None, min_length=1)):
929
- team = get_team_by_id(team_id, teams)
930
- if team is None:
931
- raise HTTPException(status_code=404, detail="Team not found")
932
-
933
- if team.storage is None:
934
- raise HTTPException(status_code=404, detail="Team does not have storage enabled")
935
-
936
- try:
937
- all_team_sessions: List[TeamSession] = team.storage.get_all_sessions(user_id=user_id, entity_id=team_id) # type: ignore
938
- except Exception as e:
939
- raise HTTPException(status_code=500, detail=f"Error retrieving sessions: {str(e)}")
940
-
941
- team_sessions: List[TeamSessionResponse] = []
942
- for session in all_team_sessions:
943
- title = get_session_title_from_team_session(session)
944
- team_sessions.append(
945
- TeamSessionResponse(
946
- title=title,
947
- session_id=session.session_id,
948
- session_name=session.session_data.get("session_name") if session.session_data else None,
949
- created_at=session.created_at,
950
- updated_at=session.updated_at,
951
- )
952
- )
953
- return team_sessions
954
-
955
- @playground_router.get("/teams/{team_id}/sessions/{session_id}")
956
- async def get_team_session(team_id: str, session_id: str, user_id: Optional[str] = Query(None, min_length=1)):
957
- team = get_team_by_id(team_id, teams)
958
- if team is None:
959
- raise HTTPException(status_code=404, detail="Team not found")
960
-
961
- if team.storage is None:
962
- raise HTTPException(status_code=404, detail="Team does not have storage enabled")
963
-
964
- try:
965
- team_session: Optional[TeamSession] = team.storage.read(session_id, user_id) # type: ignore
966
- except Exception as e:
967
- raise HTTPException(status_code=500, detail=f"Error retrieving session: {str(e)}")
968
-
969
- if not team_session:
970
- raise HTTPException(status_code=404, detail="Session not found")
971
-
972
- team_session_dict = team_session.to_dict()
973
- if team_session.memory is not None:
974
- runs = team_session.memory.get("runs")
975
- if runs is not None:
976
- first_run = runs[0]
977
- # This is how we know it is a RunResponse or RunPaused
978
- if "content" in first_run or first_run.get("is_paused", False) or first_run.get("event") == "RunPaused":
979
- team_session_dict["runs"] = []
980
- for run in runs:
981
- # We skip runs that are not from the parent team
982
- if run.get("team_session_id") is not None and run.get("team_session_id") == session_id:
983
- continue
984
-
985
- first_user_message = None
986
- for msg in run.get("messages", []):
987
- if msg.get("role") == "user" and msg.get("from_history", False) is False:
988
- first_user_message = msg
989
- break
990
- # Remove the memory from the response
991
- team_session_dict.pop("memory", None)
992
- team_session_dict["runs"].append(
993
- {
994
- "message": first_user_message,
995
- "response": run,
996
- }
997
- )
998
-
999
- return team_session_dict
1000
-
1001
- @playground_router.post("/teams/{team_id}/sessions/{session_id}/rename")
1002
- async def rename_team_session(team_id: str, session_id: str, body: TeamRenameRequest):
1003
- team = get_team_by_id(team_id, teams)
1004
- if team is None:
1005
- raise HTTPException(status_code=404, detail="Team not found")
1006
-
1007
- if team.storage is None:
1008
- raise HTTPException(status_code=404, detail="Team does not have storage enabled")
1009
-
1010
- all_team_sessions: List[TeamSession] = team.storage.get_all_sessions(user_id=body.user_id, entity_id=team_id) # type: ignore
1011
- for session in all_team_sessions:
1012
- if session.session_id == session_id:
1013
- team.rename_session(body.name, session_id=session_id)
1014
- return JSONResponse(content={"message": f"successfully renamed team session {body.name}"})
1015
-
1016
- raise HTTPException(status_code=404, detail="Session not found")
1017
-
1018
- @playground_router.delete("/teams/{team_id}/sessions/{session_id}")
1019
- async def delete_team_session(team_id: str, session_id: str, user_id: Optional[str] = Query(None, min_length=1)):
1020
- team = get_team_by_id(team_id, teams)
1021
- if team is None:
1022
- raise HTTPException(status_code=404, detail="Team not found")
1023
-
1024
- if team.storage is None:
1025
- raise HTTPException(status_code=404, detail="Team does not have storage enabled")
1026
-
1027
- all_team_sessions: List[TeamSession] = team.storage.get_all_sessions(user_id=user_id, entity_id=team_id) # type: ignore
1028
- for session in all_team_sessions:
1029
- if session.session_id == session_id:
1030
- team.delete_session(session_id)
1031
- return JSONResponse(content={"message": f"successfully deleted team session {session_id}"})
1032
-
1033
- raise HTTPException(status_code=404, detail="Session not found")
1034
-
1035
- @playground_router.get("/team/{team_id}/memories")
1036
- async def get_team_memories(team_id: str, user_id: str = Query(..., min_length=1)):
1037
- team = get_team_by_id(team_id, teams)
1038
- if team is None:
1039
- return JSONResponse(status_code=404, content="Teem not found.")
1040
-
1041
- if team.memory is None:
1042
- return JSONResponse(status_code=404, content="Team does not have memory enabled.")
1043
-
1044
- if isinstance(team.memory, Memory):
1045
- memories = team.memory.get_user_memories(user_id=user_id)
1046
- return [
1047
- MemoryResponse(memory=memory.memory, topics=memory.topics, last_updated=memory.last_updated)
1048
- for memory in memories
1049
- ]
1050
- else:
1051
- return []
1052
-
1053
- return playground_router