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
agno/storage/mysql.py DELETED
@@ -1,685 +0,0 @@
1
- import time
2
- from typing import List, Literal, Optional
3
-
4
- from agno.storage.base import Storage
5
- from agno.storage.session import Session
6
- from agno.storage.session.agent import AgentSession
7
- from agno.storage.session.team import TeamSession
8
- from agno.storage.session.v2.workflow import WorkflowSession as WorkflowSessionV2
9
- from agno.storage.session.workflow import WorkflowSession
10
- from agno.utils.log import log_debug, log_info, log_warning, logger
11
-
12
- try:
13
- from sqlalchemy.dialects import mysql
14
- from sqlalchemy.engine import Engine, create_engine
15
- from sqlalchemy.inspection import inspect
16
- from sqlalchemy.orm import scoped_session, sessionmaker
17
- from sqlalchemy.schema import Column, MetaData, Table
18
- from sqlalchemy.sql.expression import select, text
19
- from sqlalchemy.types import JSON, BigInteger, String
20
- except ImportError:
21
- raise ImportError("`sqlalchemy` not installed. Please install it using `pip install sqlalchemy pymysql`")
22
-
23
-
24
- class MySQLStorage(Storage):
25
- def __init__(
26
- self,
27
- table_name: str,
28
- schema: Optional[str] = "ai",
29
- db_url: Optional[str] = None,
30
- db_engine: Optional[Engine] = None,
31
- schema_version: int = 1,
32
- auto_upgrade_schema: bool = False,
33
- mode: Optional[Literal["agent", "team", "workflow", "workflow_v2"]] = "agent",
34
- ):
35
- """
36
- This class provides agent storage using a MySQL table.
37
-
38
- The following order is used to determine the database connection:
39
- 1. Use the db_engine if provided
40
- 2. Use the db_url
41
- 3. Raise an error if neither is provided
42
-
43
- Args:
44
- table_name (str): Name of the table to store Agent sessions.
45
- schema (Optional[str]): The schema to use for the table. Defaults to "ai".
46
- db_url (Optional[str]): The database URL to connect to.
47
- db_engine (Optional[Engine]): The SQLAlchemy database engine to use.
48
- schema_version (int): Version of the schema. Defaults to 1.
49
- auto_upgrade_schema (bool): Whether to automatically upgrade the schema.
50
- mode (Optional[Literal["agent", "team", "workflow", "workflow_v2"]]): The mode of the storage.
51
- Raises:
52
- ValueError: If neither db_url nor db_engine is provided.
53
- """
54
- super().__init__(mode)
55
- _engine: Optional[Engine] = db_engine
56
- if _engine is None and db_url is not None:
57
- _engine = create_engine(db_url)
58
-
59
- if _engine is None:
60
- raise ValueError("Must provide either db_url or db_engine")
61
-
62
- # Database attributes
63
- self.table_name: str = table_name
64
- self.schema: Optional[str] = schema
65
- self.db_url: Optional[str] = db_url
66
- self.db_engine: Engine = _engine
67
- self.metadata: MetaData = MetaData(schema=self.schema)
68
- self.inspector = inspect(self.db_engine)
69
-
70
- # Table schema version
71
- self.schema_version: int = schema_version
72
- # Automatically upgrade schema if True
73
- self.auto_upgrade_schema: bool = auto_upgrade_schema
74
- self._schema_up_to_date: bool = False
75
-
76
- # Database session
77
- self.Session: scoped_session = scoped_session(sessionmaker(bind=self.db_engine))
78
- # Database table for storage
79
- self.table: Table = self.get_table()
80
- log_debug(f"Created MySQLStorage: '{self.schema}.{self.table_name}'")
81
-
82
- @property
83
- def mode(self) -> Literal["agent", "team", "workflow", "workflow_v2"]:
84
- """Get the mode of the storage."""
85
- return super().mode
86
-
87
- @mode.setter
88
- def mode(self, value: Optional[Literal["agent", "team", "workflow", "workflow_v2"]]) -> None:
89
- """Set the mode and refresh the table if mode changes."""
90
- super(MySQLStorage, type(self)).mode.fset(self, value) # type: ignore
91
- if value is not None:
92
- self.table = self.get_table()
93
-
94
- def get_table_v1(self) -> Table:
95
- """
96
- Define the table schema for version 1.
97
-
98
- Returns:
99
- Table: SQLAlchemy Table object representing the schema.
100
- """
101
- # Common columns for both agent and workflow modes
102
- common_columns = [
103
- Column("session_id", String(255), primary_key=True),
104
- Column("user_id", String(255), index=True),
105
- Column("memory", JSON),
106
- Column("session_data", JSON),
107
- Column("extra_data", JSON),
108
- Column("created_at", BigInteger, server_default=text("UNIX_TIMESTAMP()")),
109
- Column("updated_at", BigInteger, server_onupdate=text("UNIX_TIMESTAMP()")),
110
- ]
111
-
112
- # Mode-specific columns
113
- specific_columns = []
114
- if self.mode == "agent":
115
- specific_columns = [
116
- Column("agent_id", String(255), index=True),
117
- Column("team_session_id", String(255), index=True, nullable=True),
118
- Column("agent_data", JSON),
119
- ]
120
- elif self.mode == "team":
121
- specific_columns = [
122
- Column("team_id", String(255), index=True),
123
- Column("team_session_id", String(255), index=True, nullable=True),
124
- Column("team_data", JSON),
125
- ]
126
- elif self.mode == "workflow":
127
- specific_columns = [
128
- Column("workflow_id", String(255), index=True),
129
- Column("workflow_data", JSON),
130
- ]
131
- elif self.mode == "workflow_v2":
132
- specific_columns = [
133
- Column("workflow_id", String(255), index=True),
134
- Column("workflow_name", String(255), index=True),
135
- Column("workflow_data", JSON),
136
- Column("runs", JSON),
137
- ]
138
- # Create table with all columns
139
- table = Table(
140
- self.table_name,
141
- self.metadata,
142
- *common_columns,
143
- *specific_columns,
144
- extend_existing=True,
145
- schema=self.schema, # type: ignore
146
- )
147
-
148
- return table
149
-
150
- def get_table(self) -> Table:
151
- """
152
- Get the table schema based on the schema version.
153
-
154
- Returns:
155
- Table: SQLAlchemy Table object for the current schema version.
156
-
157
- Raises:
158
- ValueError: If an unsupported schema version is specified.
159
- """
160
- if self.schema_version == 1:
161
- return self.get_table_v1()
162
- else:
163
- raise ValueError(f"Unsupported schema version: {self.schema_version}")
164
-
165
- def table_exists(self) -> bool:
166
- """
167
- Check if the table exists in the database.
168
-
169
- Returns:
170
- bool: True if the table exists, False otherwise.
171
- """
172
- try:
173
- # Use a direct SQL query to check if the table exists
174
- with self.Session() as sess:
175
- if self.schema is not None:
176
- exists_query = text(
177
- "SELECT 1 FROM information_schema.tables WHERE table_schema = :schema AND table_name = :table"
178
- )
179
- exists = (
180
- sess.execute(exists_query, {"schema": self.schema, "table": self.table_name}).scalar()
181
- is not None
182
- )
183
- else:
184
- exists_query = text("SELECT 1 FROM information_schema.tables WHERE table_name = :table")
185
- exists = sess.execute(exists_query, {"table": self.table_name}).scalar() is not None
186
-
187
- log_debug(f"Table '{self.table.fullname}' does{' not ' if not exists else ' '}exist")
188
- return exists
189
-
190
- except Exception as e:
191
- logger.error(f"Error checking if table exists: {e}")
192
- return False
193
-
194
- def create(self) -> None:
195
- """
196
- Create the table if it does not exist.
197
- """
198
- self.table = self.get_table()
199
- if not self.table_exists():
200
- try:
201
- with self.Session() as sess, sess.begin():
202
- if self.schema is not None:
203
- log_debug(f"Creating schema: {self.schema}")
204
- sess.execute(text(f"CREATE SCHEMA IF NOT EXISTS `{self.schema}`;"))
205
-
206
- log_debug(f"Creating table: {self.table_name}")
207
-
208
- # First create the table without indexes
209
- table_without_indexes = Table(
210
- self.table_name,
211
- MetaData(schema=self.schema),
212
- *[c.copy() for c in self.table.columns],
213
- schema=self.schema,
214
- )
215
- table_without_indexes.create(self.db_engine, checkfirst=True)
216
-
217
- # Then create each index individually with error handling
218
- for idx in self.table.indexes:
219
- try:
220
- idx_name = idx.name
221
- log_debug(f"Creating index: {idx_name}")
222
-
223
- # Check if index already exists in MySQL
224
- with self.Session() as sess:
225
- if self.schema:
226
- exists_query = text(
227
- """SELECT 1 FROM information_schema.statistics
228
- WHERE table_schema = :schema
229
- AND table_name = :table
230
- AND index_name = :index_name"""
231
- )
232
- exists = (
233
- sess.execute(
234
- exists_query,
235
- {"schema": self.schema, "table": self.table_name, "index_name": idx_name},
236
- ).scalar()
237
- is not None
238
- )
239
- else:
240
- exists_query = text(
241
- """SELECT 1 FROM information_schema.statistics
242
- WHERE table_name = :table
243
- AND index_name = :index_name"""
244
- )
245
- exists = (
246
- sess.execute(
247
- exists_query, {"table": self.table_name, "index_name": idx_name}
248
- ).scalar()
249
- is not None
250
- )
251
-
252
- if not exists:
253
- idx.create(self.db_engine)
254
- else:
255
- log_debug(f"Index {idx_name} already exists, skipping creation")
256
-
257
- except Exception as e:
258
- # Log the error but continue with other indexes
259
- logger.warning(f"Error creating index {idx.name}: {e}")
260
-
261
- except Exception as e:
262
- logger.error(f"Could not create table: '{self.table.fullname}': {e}")
263
- raise
264
-
265
- def read(self, session_id: str, user_id: Optional[str] = None) -> Optional[Session]:
266
- """
267
- Read an Session from the database.
268
-
269
- Args:
270
- session_id (str): ID of the session to read.
271
- user_id (Optional[str]): User ID to filter by. Defaults to None.
272
-
273
- Returns:
274
- Optional[Session]: Session object if found, None otherwise.
275
- """
276
- try:
277
- with self.Session() as sess:
278
- stmt = select(self.table).where(self.table.c.session_id == session_id)
279
- if user_id:
280
- stmt = stmt.where(self.table.c.user_id == user_id)
281
- result = sess.execute(stmt).fetchone()
282
- if self.mode == "agent":
283
- return AgentSession.from_dict(result._mapping) if result is not None else None
284
- elif self.mode == "team":
285
- return TeamSession.from_dict(result._mapping) if result is not None else None
286
- elif self.mode == "workflow":
287
- return WorkflowSession.from_dict(result._mapping) if result is not None else None
288
- elif self.mode == "workflow_v2":
289
- return WorkflowSessionV2.from_dict(result._mapping) if result is not None else None
290
- except Exception as e:
291
- if "doesn't exist" in str(e) or "doesn't exist" in str(e):
292
- log_debug(f"Table does not exist: {self.table.name}")
293
- log_debug("Creating table for future transactions")
294
- self.create()
295
- else:
296
- log_debug(f"Exception reading from table: {e}")
297
- return None
298
-
299
- def get_all_session_ids(self, user_id: Optional[str] = None, entity_id: Optional[str] = None) -> List[str]:
300
- """
301
- Get all session IDs, optionally filtered by user_id and/or entity_id.
302
-
303
- Args:
304
- user_id (Optional[str]): The ID of the user to filter by.
305
- entity_id (Optional[str]): The ID of the agent / workflow to filter by.
306
-
307
- Returns:
308
- List[str]: List of session IDs matching the criteria.
309
- """
310
- try:
311
- with self.Session() as sess, sess.begin():
312
- # get all session_ids
313
- stmt = select(self.table.c.session_id)
314
- if user_id is not None:
315
- stmt = stmt.where(self.table.c.user_id == user_id)
316
- if entity_id is not None:
317
- if self.mode == "agent":
318
- stmt = stmt.where(self.table.c.agent_id == entity_id)
319
- elif self.mode == "team":
320
- stmt = stmt.where(self.table.c.team_id == entity_id)
321
- elif self.mode == "workflow":
322
- stmt = stmt.where(self.table.c.workflow_id == entity_id)
323
- elif self.mode == "workflow_v2":
324
- stmt = stmt.where(self.table.c.workflow_id == entity_id)
325
- # order by created_at desc
326
- stmt = stmt.order_by(self.table.c.created_at.desc())
327
- # execute query
328
- rows = sess.execute(stmt).fetchall()
329
- return [row[0] for row in rows] if rows is not None else []
330
- except Exception as e:
331
- log_debug(f"Exception reading from table: {e}")
332
- log_debug(f"Table does not exist: {self.table.name}")
333
- log_debug("Creating table for future transactions")
334
- self.create()
335
- return []
336
-
337
- def get_all_sessions(self, user_id: Optional[str] = None, entity_id: Optional[str] = None) -> List[Session]:
338
- """
339
- Get all sessions, optionally filtered by user_id and/or entity_id.
340
-
341
- Args:
342
- user_id (Optional[str]): The ID of the user to filter by.
343
- entity_id (Optional[str]): The ID of the agent / workflow to filter by.
344
-
345
- Returns:
346
- List[Session]: List of Session objects matching the criteria.
347
- """
348
- try:
349
- with self.Session() as sess, sess.begin():
350
- # get all sessions
351
- stmt = select(self.table)
352
- if user_id is not None:
353
- stmt = stmt.where(self.table.c.user_id == user_id)
354
- if entity_id is not None:
355
- if self.mode == "agent":
356
- stmt = stmt.where(self.table.c.agent_id == entity_id)
357
- elif self.mode == "team":
358
- stmt = stmt.where(self.table.c.team_id == entity_id)
359
- elif self.mode == "workflow":
360
- stmt = stmt.where(self.table.c.workflow_id == entity_id)
361
- elif self.mode == "workflow_v2":
362
- stmt = stmt.where(self.table.c.workflow_id == entity_id)
363
- # order by created_at desc
364
- stmt = stmt.order_by(self.table.c.created_at.desc())
365
- # execute query
366
- rows = sess.execute(stmt).fetchall()
367
- if rows is not None:
368
- if self.mode == "agent":
369
- return [AgentSession.from_dict(row._mapping) for row in rows] # type: ignore
370
- elif self.mode == "team":
371
- return [TeamSession.from_dict(row._mapping) for row in rows] # type: ignore
372
- elif self.mode == "workflow":
373
- return [WorkflowSession.from_dict(row._mapping) for row in rows] # type: ignore
374
- elif self.mode == "workflow_v2":
375
- return [WorkflowSessionV2.from_dict(row._mapping) for row in rows] # type: ignore[misc]
376
- else:
377
- return []
378
- except Exception as e:
379
- log_debug(f"Exception reading from table: {e}")
380
- log_debug(f"Table does not exist: {self.table.name}")
381
- log_debug("Creating table for future transactions")
382
- self.create()
383
- return []
384
-
385
- def get_recent_sessions(
386
- self,
387
- user_id: Optional[str] = None,
388
- entity_id: Optional[str] = None,
389
- limit: Optional[int] = 2,
390
- ) -> List[Session]:
391
- """Get the last N sessions, ordered by created_at descending.
392
-
393
- Args:
394
- num_history_sessions: Number of most recent sessions to return
395
- user_id: Filter by user ID
396
- entity_id: Filter by entity ID (agent_id, team_id, or workflow_id)
397
-
398
- Returns:
399
- List[Session]: List of most recent sessions
400
- """
401
- try:
402
- with self.Session() as sess, sess.begin():
403
- # Build the base query
404
- stmt = select(self.table)
405
-
406
- # Add filters
407
- if user_id is not None:
408
- stmt = stmt.where(self.table.c.user_id == user_id)
409
- if entity_id is not None:
410
- if self.mode == "agent":
411
- stmt = stmt.where(self.table.c.agent_id == entity_id)
412
- elif self.mode == "team":
413
- stmt = stmt.where(self.table.c.team_id == entity_id)
414
- elif self.mode == "workflow":
415
- stmt = stmt.where(self.table.c.workflow_id == entity_id)
416
- elif self.mode == "workflow_v2":
417
- stmt = stmt.where(self.table.c.workflow_id == entity_id)
418
- # Order by created_at desc and limit results
419
- stmt = stmt.order_by(self.table.c.created_at.desc())
420
- if limit is not None:
421
- stmt = stmt.limit(limit)
422
-
423
- # Execute query
424
- rows = sess.execute(stmt).fetchall()
425
- if rows is not None:
426
- sessions: List[Session] = []
427
- for row in rows:
428
- session: Optional[Session] = None
429
- if self.mode == "agent":
430
- session = AgentSession.from_dict(row._mapping) # type: ignore
431
- elif self.mode == "team":
432
- session = TeamSession.from_dict(row._mapping) # type: ignore
433
- elif self.mode == "workflow":
434
- session = WorkflowSession.from_dict(row._mapping) # type: ignore
435
- elif self.mode == "workflow_v2":
436
- session = WorkflowSessionV2.from_dict(row._mapping) # type: ignore
437
- if session is not None:
438
- sessions.append(session)
439
- return sessions
440
- return []
441
-
442
- except Exception as e:
443
- if "doesn't exist" in str(e) or "doesn't exist" in str(e):
444
- log_debug(f"Table does not exist: {self.table.name}")
445
- log_debug("Creating table for future transactions")
446
- self.create()
447
- else:
448
- log_debug(f"Exception reading from table: {e}")
449
- return []
450
-
451
- def upgrade_schema(self) -> None:
452
- """
453
- Upgrade the schema to the latest version.
454
- Currently handles adding the team_session_id column for agent mode.
455
- """
456
- if not self.auto_upgrade_schema:
457
- log_debug("Auto schema upgrade disabled. Skipping upgrade.")
458
- return
459
-
460
- try:
461
- if self.mode == "agent" and self.table_exists():
462
- with self.Session() as sess:
463
- # Check if team_session_id column exists
464
- column_exists_query = text(
465
- """
466
- SELECT 1 FROM information_schema.columns
467
- WHERE table_schema = :schema AND table_name = :table
468
- AND column_name = 'team_session_id'
469
- """
470
- )
471
- column_exists = (
472
- sess.execute(column_exists_query, {"schema": self.schema, "table": self.table_name}).scalar()
473
- is not None
474
- )
475
-
476
- if not column_exists:
477
- log_info(f"Adding 'team_session_id' column to {self.schema}.{self.table_name}")
478
- alter_table_query = text(
479
- f"ALTER TABLE `{self.schema}`.`{self.table_name}` ADD COLUMN team_session_id VARCHAR(255)"
480
- )
481
- sess.execute(alter_table_query)
482
- sess.commit()
483
- self._schema_up_to_date = True
484
- log_info("Schema upgrade completed successfully")
485
- except Exception as e:
486
- logger.error(f"Error during schema upgrade: {e}")
487
- raise
488
-
489
- def upsert(self, session: Session, create_and_retry: bool = True) -> Optional[Session]:
490
- """
491
- Insert or update an Session in the database.
492
-
493
- Args:
494
- session (Session): The session data to upsert.
495
- create_and_retry (bool): Retry upsert if table does not exist.
496
-
497
- Returns:
498
- Optional[Session]: The upserted Session, or None if operation failed.
499
- """
500
- # Perform schema upgrade if auto_upgrade_schema is enabled
501
- if self.auto_upgrade_schema and not self._schema_up_to_date:
502
- self.upgrade_schema()
503
-
504
- try:
505
- with self.Session() as sess, sess.begin():
506
- # Create an insert statement
507
- if self.mode == "agent":
508
- stmt = mysql.insert(self.table).values(
509
- session_id=session.session_id,
510
- agent_id=session.agent_id, # type: ignore
511
- team_session_id=session.team_session_id, # type: ignore
512
- user_id=session.user_id,
513
- memory=getattr(session, "memory", None),
514
- agent_data=session.agent_data, # type: ignore
515
- session_data=session.session_data,
516
- extra_data=session.extra_data,
517
- )
518
- # Define the upsert if the session_id already exists
519
- # See: https://docs.sqlalchemy.org/en/20/dialects/mysql.html#insert-on-duplicate-key-update
520
- stmt = stmt.on_duplicate_key_update(
521
- agent_id=session.agent_id, # type: ignore
522
- team_session_id=session.team_session_id, # type: ignore
523
- user_id=session.user_id,
524
- memory=getattr(session, "memory", None),
525
- agent_data=session.agent_data, # type: ignore
526
- session_data=session.session_data,
527
- extra_data=session.extra_data,
528
- updated_at=int(time.time()),
529
- )
530
- elif self.mode == "team":
531
- stmt = mysql.insert(self.table).values(
532
- session_id=session.session_id,
533
- team_id=session.team_id, # type: ignore
534
- user_id=session.user_id,
535
- team_session_id=session.team_session_id, # type: ignore
536
- memory=getattr(session, "memory", None),
537
- team_data=session.team_data, # type: ignore
538
- session_data=session.session_data,
539
- extra_data=session.extra_data,
540
- )
541
- # Define the upsert if the session_id already exists
542
- # See: https://docs.sqlalchemy.org/en/20/dialects/mysql.html#insert-on-duplicate-key-update
543
- stmt = stmt.on_duplicate_key_update(
544
- team_id=session.team_id, # type: ignore
545
- user_id=session.user_id,
546
- team_session_id=session.team_session_id, # type: ignore
547
- memory=getattr(session, "memory", None),
548
- team_data=session.team_data, # type: ignore
549
- session_data=session.session_data,
550
- extra_data=session.extra_data,
551
- updated_at=int(time.time()),
552
- )
553
- elif self.mode == "workflow":
554
- stmt = mysql.insert(self.table).values(
555
- session_id=session.session_id,
556
- workflow_id=session.workflow_id, # type: ignore
557
- user_id=session.user_id,
558
- memory=getattr(session, "memory", None),
559
- workflow_data=session.workflow_data, # type: ignore
560
- session_data=session.session_data,
561
- extra_data=session.extra_data,
562
- )
563
- # Define the upsert if the session_id already exists
564
- # See: https://docs.sqlalchemy.org/en/20/dialects/mysql.html#insert-on-duplicate-key-update
565
- stmt = stmt.on_duplicate_key_update(
566
- workflow_id=session.workflow_id, # type: ignore
567
- user_id=session.user_id,
568
- memory=getattr(session, "memory", None),
569
- workflow_data=session.workflow_data, # type: ignore
570
- session_data=session.session_data,
571
- extra_data=session.extra_data,
572
- updated_at=int(time.time()),
573
- )
574
- elif self.mode == "workflow_v2":
575
- # Convert session to dict to ensure proper serialization
576
- session_dict = session.to_dict()
577
-
578
- stmt = mysql.insert(self.table).values(
579
- session_id=session.session_id,
580
- workflow_id=session.workflow_id, # type: ignore
581
- workflow_name=session.workflow_name, # type: ignore
582
- user_id=session.user_id,
583
- runs=session_dict.get("runs"),
584
- workflow_data=session.workflow_data, # type: ignore
585
- session_data=session.session_data,
586
- extra_data=session.extra_data,
587
- )
588
- # Define the upsert if the session_id already exists
589
- # See: https://docs.sqlalchemy.org/en/20/dialects/mysql.html#insert-on-duplicate-key-update
590
- stmt = stmt.on_duplicate_key_update(
591
- workflow_id=session.workflow_id, # type: ignore
592
- workflow_name=session.workflow_name, # type: ignore
593
- user_id=session.user_id,
594
- runs=session_dict.get("runs"), # type: ignore
595
- workflow_data=session.workflow_data, # type: ignore
596
- session_data=session.session_data,
597
- extra_data=session.extra_data,
598
- updated_at=int(time.time()),
599
- )
600
- sess.execute(stmt)
601
- except Exception as e:
602
- if create_and_retry and not self.table_exists():
603
- log_debug(f"Table does not exist: {self.table.name}")
604
- log_debug("Creating table and retrying upsert")
605
- self.create()
606
- return self.upsert(session, create_and_retry=False)
607
- else:
608
- log_warning(f"Exception upserting into table: {e}")
609
- log_warning(
610
- "A table upgrade might be required, please review these docs for more information: https://agno.link/upgrade-schema"
611
- )
612
- return None
613
- return self.read(session_id=session.session_id)
614
-
615
- def delete_session(self, session_id: Optional[str] = None):
616
- """
617
- Delete a session from the database.
618
-
619
- Args:
620
- session_id (Optional[str], optional): ID of the session to delete. Defaults to None.
621
-
622
- Raises:
623
- Exception: If an error occurs during deletion.
624
- """
625
- if session_id is None:
626
- logger.warning("No session_id provided for deletion.")
627
- return
628
-
629
- try:
630
- with self.Session() as sess, sess.begin():
631
- # Delete the session with the given session_id
632
- delete_stmt = self.table.delete().where(self.table.c.session_id == session_id)
633
- result = sess.execute(delete_stmt)
634
- if result.rowcount == 0:
635
- log_debug(f"No session found with session_id: {session_id}")
636
- else:
637
- log_debug(f"Successfully deleted session with session_id: {session_id}")
638
- except Exception as e:
639
- logger.error(f"Error deleting session: {e}")
640
-
641
- def drop(self) -> None:
642
- """
643
- Drop the table from the database if it exists.
644
- """
645
- if self.table_exists():
646
- log_debug(f"Deleting table: {self.table_name}")
647
- # Drop with checkfirst=True to avoid errors if the table doesn't exist
648
- self.table.drop(self.db_engine, checkfirst=True)
649
- # Clear metadata to ensure indexes are recreated properly
650
- self.metadata = MetaData(schema=self.schema)
651
- self.table = self.get_table()
652
-
653
- def __deepcopy__(self, memo):
654
- """
655
- Create a deep copy of the MySQLStorage instance, handling unpickleable attributes.
656
-
657
- Args:
658
- memo (dict): A dictionary of objects already copied during the current copying pass.
659
-
660
- Returns:
661
- MySQLStorage: A deep-copied instance of MySQLStorage.
662
- """
663
- from copy import deepcopy
664
-
665
- # Create a new instance without calling __init__
666
- cls = self.__class__
667
- copied_obj = cls.__new__(cls)
668
- memo[id(self)] = copied_obj
669
-
670
- # Deep copy attributes
671
- for k, v in self.__dict__.items():
672
- if k in {"metadata", "table", "inspector"}:
673
- continue
674
- # Reuse db_engine and Session without copying
675
- elif k in {"db_engine", "SqlSession"}:
676
- setattr(copied_obj, k, v)
677
- else:
678
- setattr(copied_obj, k, deepcopy(v, memo))
679
-
680
- # Recreate metadata and table for the copied instance
681
- copied_obj.metadata = MetaData(schema=copied_obj.schema)
682
- copied_obj.inspector = inspect(copied_obj.db_engine)
683
- copied_obj.table = copied_obj.get_table()
684
-
685
- return copied_obj