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,214 +0,0 @@
1
- from typing import Any, Dict, List, Optional
2
-
3
- try:
4
- from sqlalchemy.dialects import postgresql
5
- from sqlalchemy.engine import Engine, create_engine
6
- from sqlalchemy.inspection import inspect
7
- from sqlalchemy.orm import scoped_session, sessionmaker
8
- from sqlalchemy.schema import Column, MetaData, Table
9
- from sqlalchemy.sql.expression import delete, select, text
10
- from sqlalchemy.types import DateTime, String
11
- except ImportError:
12
- raise ImportError("`sqlalchemy` not installed. Please install using `pip install sqlalchemy 'psycopg[binary]'`")
13
-
14
- from agno.memory.v2.db.base import MemoryDb
15
- from agno.memory.v2.db.schema import MemoryRow
16
- from agno.utils.log import log_debug, log_info, logger
17
-
18
-
19
- class PostgresMemoryDb(MemoryDb):
20
- def __init__(
21
- self,
22
- table_name: str,
23
- schema: Optional[str] = "ai",
24
- db_url: Optional[str] = None,
25
- db_engine: Optional[Engine] = None,
26
- ):
27
- """
28
- This class provides a memory store backed by a postgres table.
29
-
30
- The following order is used to determine the database connection:
31
- 1. Use the db_engine if provided
32
- 2. Use the db_url to create the engine
33
-
34
- Args:
35
- table_name (str): The name of the table to store memory rows.
36
- schema (Optional[str]): The schema to store the table in. Defaults to "ai".
37
- db_url (Optional[str]): The database URL to connect to. Defaults to None.
38
- db_engine (Optional[Engine]): The database engine to use. Defaults to None.
39
- """
40
- _engine: Optional[Engine] = db_engine
41
- if _engine is None and db_url is not None:
42
- _engine = create_engine(db_url)
43
-
44
- if _engine is None:
45
- raise ValueError("Must provide either db_url or db_engine")
46
-
47
- self.table_name: str = table_name
48
- self.schema: Optional[str] = schema
49
- self.db_url: Optional[str] = db_url
50
- self.db_engine: Engine = _engine
51
- self.inspector = inspect(self.db_engine)
52
- self.metadata: MetaData = MetaData(schema=self.schema)
53
- self.Session: scoped_session = scoped_session(sessionmaker(bind=self.db_engine))
54
- self.table: Table = self.get_table()
55
-
56
- def __dict__(self) -> Dict[str, Any]:
57
- return {
58
- "name": "PostgresMemoryDb",
59
- "table_name": self.table_name,
60
- "schema": self.schema,
61
- }
62
-
63
- def get_table(self) -> Table:
64
- return Table(
65
- self.table_name,
66
- self.metadata,
67
- Column("id", String, primary_key=True),
68
- Column("user_id", String, index=True),
69
- Column("memory", postgresql.JSONB, server_default=text("'{}'::jsonb")),
70
- Column("created_at", DateTime(timezone=True), server_default=text("now()")),
71
- Column("updated_at", DateTime(timezone=True), onupdate=text("now()")),
72
- extend_existing=True,
73
- )
74
-
75
- def create(self) -> None:
76
- if not self.table_exists():
77
- try:
78
- with self.Session() as sess, sess.begin():
79
- if self.schema is not None:
80
- log_debug(f"Creating schema: {self.schema}")
81
- sess.execute(text(f"CREATE SCHEMA IF NOT EXISTS {self.schema};"))
82
- log_debug(f"Creating table: {self.table_name}")
83
- self.table.create(self.db_engine, checkfirst=True)
84
- except Exception as e:
85
- logger.error(f"Error creating table '{self.table.fullname}': {e}")
86
- raise
87
-
88
- def memory_exists(self, memory: MemoryRow) -> bool:
89
- columns = [self.table.c.id]
90
- with self.Session() as sess, sess.begin():
91
- stmt = select(*columns).where(self.table.c.id == memory.id)
92
- result = sess.execute(stmt).first()
93
- return result is not None
94
-
95
- def read_memories(
96
- self, user_id: Optional[str] = None, limit: Optional[int] = None, sort: Optional[str] = None
97
- ) -> List[MemoryRow]:
98
- memories: List[MemoryRow] = []
99
- try:
100
- with self.Session() as sess, sess.begin():
101
- stmt = select(self.table)
102
- if user_id is not None:
103
- stmt = stmt.where(self.table.c.user_id == user_id)
104
- if limit is not None:
105
- stmt = stmt.limit(limit)
106
-
107
- if sort == "asc":
108
- stmt = stmt.order_by(self.table.c.created_at.asc())
109
- else:
110
- stmt = stmt.order_by(self.table.c.created_at.desc())
111
-
112
- rows = sess.execute(stmt).fetchall()
113
- for row in rows:
114
- if row is not None:
115
- memories.append(MemoryRow.model_validate(row))
116
- except Exception as e:
117
- log_debug(f"Exception reading from table: {e}")
118
- log_debug(f"Table does not exist: {self.table.name}")
119
- log_debug("Creating table for future transactions")
120
- self.create()
121
- return memories
122
-
123
- def upsert_memory(self, memory: MemoryRow, create_and_retry: bool = True) -> None:
124
- """Create a new memory if it does not exist, otherwise update the existing memory"""
125
-
126
- try:
127
- with self.Session() as sess, sess.begin():
128
- # Create an insert statement
129
- stmt = postgresql.insert(self.table).values(
130
- id=memory.id,
131
- user_id=memory.user_id,
132
- memory=memory.memory,
133
- )
134
-
135
- # Define the upsert if the memory already exists
136
- # See: https://docs.sqlalchemy.org/en/20/dialects/postgresql.html#postgresql-insert-on-conflict
137
- stmt = stmt.on_conflict_do_update(
138
- index_elements=["id"],
139
- set_=dict(
140
- user_id=stmt.excluded.user_id,
141
- memory=stmt.excluded.memory,
142
- ),
143
- )
144
-
145
- sess.execute(stmt)
146
- except Exception as e:
147
- log_debug(f"Exception upserting into table: {e}")
148
- log_debug(f"Table does not exist: {self.table.name}")
149
- log_debug("Creating table for future transactions")
150
- self.create()
151
- if create_and_retry:
152
- return self.upsert_memory(memory, create_and_retry=False)
153
- return None
154
-
155
- def delete_memory(self, memory_id: str) -> None:
156
- with self.Session() as sess, sess.begin():
157
- stmt = delete(self.table).where(self.table.c.id == memory_id)
158
- sess.execute(stmt)
159
-
160
- def drop_table(self) -> None:
161
- if self.table_exists():
162
- log_debug(f"Deleting table: {self.table_name}")
163
- self.table.drop(self.db_engine)
164
-
165
- def table_exists(self) -> bool:
166
- log_debug(f"Checking if table exists: {self.table.name}")
167
- try:
168
- return inspect(self.db_engine).has_table(self.table.name, schema=self.schema)
169
- except Exception as e:
170
- logger.error(e)
171
- return False
172
-
173
- def clear(self) -> bool:
174
- if self.table_exists():
175
- with self.Session() as sess, sess.begin():
176
- stmt = delete(self.table)
177
- log_info(f"Clearing table: {self.table.name}")
178
- sess.execute(stmt)
179
- return True
180
- return False
181
-
182
- def __deepcopy__(self, memo):
183
- """
184
- Create a deep copy of the PgMemoryDb instance, handling unpickleable attributes.
185
-
186
- Args:
187
- memo (dict): A dictionary of objects already copied during the current copying pass.
188
-
189
- Returns:
190
- PostgresMemoryDb: A deep-copied instance of PgMemoryDb.
191
- """
192
- from copy import deepcopy
193
-
194
- # Create a new instance without calling __init__
195
- cls = self.__class__
196
- copied_obj = cls.__new__(cls)
197
- memo[id(self)] = copied_obj
198
-
199
- # Deep copy attributes
200
-
201
- for k, v in self.__dict__().items():
202
- if k in {"metadata", "table"}:
203
- continue
204
- # Reuse db_engine and Session without copying
205
- elif k in {"db_engine", "Session"}:
206
- setattr(copied_obj, k, v)
207
- else:
208
- setattr(copied_obj, k, deepcopy(v, memo))
209
-
210
- # Recreate metadata and table for the copied instance
211
- copied_obj.metadata = MetaData(schema=copied_obj.schema)
212
- copied_obj.table = copied_obj.get_table()
213
-
214
- return copied_obj
@@ -1,187 +0,0 @@
1
- import json
2
- import time
3
- from typing import Any, Dict, List, Optional
4
-
5
- try:
6
- from redis import ConnectionError, Redis
7
- except ImportError:
8
- raise ImportError("`redis` not installed. Please install it using `pip install redis`")
9
-
10
- from agno.memory.v2.db.base import MemoryDb
11
- from agno.memory.v2.db.schema import MemoryRow
12
- from agno.utils.log import log_debug, log_info, logger
13
-
14
-
15
- class RedisMemoryDb(MemoryDb):
16
- def __init__(
17
- self,
18
- prefix: str = "agno_memory",
19
- host: str = "localhost",
20
- port: int = 6379,
21
- db: int = 0,
22
- password: Optional[str] = None,
23
- ssl: Optional[bool] = False,
24
- expire: Optional[int] = None,
25
- ):
26
- """
27
- Initialize Redis memory store.
28
-
29
- Args:
30
- prefix (str): Prefix for Redis keys to namespace the memories
31
- host (str): Redis host address
32
- port (int): Redis port number
33
- db (int): Redis database number
34
- password (Optional[str]): Redis password if authentication is required
35
- ssl (Optional[bool]): Whether to use SSL for Redis connection
36
- expire (Optional[int]): TTL (time to live) in seconds for Redis keys. None means no expiration.
37
- """
38
- self.prefix = prefix
39
- self.expire = expire
40
- self.redis_client = Redis(
41
- host=host,
42
- port=port,
43
- db=db,
44
- password=password,
45
- decode_responses=True, # Automatically decode responses to str
46
- ssl=ssl,
47
- )
48
- log_debug(f"Created RedisMemoryDb with prefix: '{self.prefix}'")
49
-
50
- def __dict__(self) -> Dict[str, Any]:
51
- return {
52
- "name": "RedisMemoryDb",
53
- "prefix": self.prefix,
54
- "expire": self.expire,
55
- }
56
-
57
- def _get_key(self, memory_id: str) -> str:
58
- """Generate Redis key for a memory."""
59
- return f"{self.prefix}:{memory_id}"
60
-
61
- def create(self) -> None:
62
- """
63
- Test connection to Redis.
64
- For Redis, we don't need to create schema as it's schema-less.
65
- """
66
- try:
67
- self.redis_client.ping()
68
- log_debug("Redis connection successful")
69
- except ConnectionError as e:
70
- logger.error(f"Could not connect to Redis: {e}")
71
- raise
72
-
73
- def memory_exists(self, memory: MemoryRow) -> bool:
74
- """Check if a memory exists"""
75
- try:
76
- key = self._get_key(memory.id) # type: ignore
77
- return self.redis_client.exists(key) > 0 # type: ignore
78
- except Exception as e:
79
- logger.error(f"Error checking memory existence: {e}")
80
- return False
81
-
82
- def read_memories(
83
- self, user_id: Optional[str] = None, limit: Optional[int] = None, sort: Optional[str] = None
84
- ) -> List[MemoryRow]:
85
- """Read memories from Redis"""
86
- memories: List[MemoryRow] = []
87
- try:
88
- # Get all keys matching the prefix pattern
89
- pattern = f"{self.prefix}:*"
90
- memory_data = []
91
-
92
- # Collect all matching memories
93
- for key in self.redis_client.scan_iter(match=pattern):
94
- data_str = self.redis_client.get(key)
95
- if data_str:
96
- data = json.loads(data_str) # type: ignore
97
-
98
- # Filter by user_id if specified
99
- if user_id is None or data.get("user_id") == user_id:
100
- memory_data.append(data)
101
-
102
- # Sort by created_at timestamp
103
- if sort == "asc":
104
- memory_data.sort(key=lambda x: x.get("created_at", 0))
105
- else:
106
- memory_data.sort(key=lambda x: x.get("created_at", 0), reverse=True)
107
-
108
- # Apply limit if specified
109
- if limit is not None and limit > 0:
110
- memory_data = memory_data[:limit]
111
-
112
- # Convert to MemoryRow objects
113
- for data in memory_data:
114
- memories.append(MemoryRow.model_validate(data))
115
-
116
- except Exception as e:
117
- logger.error(f"Error reading memories: {e}")
118
-
119
- return memories
120
-
121
- def upsert_memory(self, memory: MemoryRow) -> Optional[MemoryRow]:
122
- """Upsert a memory in Redis"""
123
- try:
124
- # Prepare data
125
- timestamp = int(time.time())
126
-
127
- # Convert to dict and handle datetime objects
128
- memory_data = memory.model_dump(mode="json")
129
-
130
- # Add timestamps if not present
131
- if "created_at" not in memory_data:
132
- memory_data["created_at"] = timestamp
133
-
134
- memory_data["updated_at"] = timestamp
135
-
136
- # Save to Redis
137
- key = self._get_key(memory.id) # type: ignore
138
- if self.expire is not None:
139
- self.redis_client.set(key, json.dumps(memory_data), ex=self.expire)
140
- else:
141
- self.redis_client.set(key, json.dumps(memory_data))
142
-
143
- return memory
144
-
145
- except Exception as e:
146
- logger.error(f"Error upserting memory: {e}")
147
- return None
148
-
149
- def delete_memory(self, memory_id: str) -> None:
150
- """Delete a memory from Redis"""
151
- try:
152
- key = self._get_key(memory_id)
153
- self.redis_client.delete(key)
154
- log_debug(f"Deleted memory: {memory_id}")
155
- except Exception as e:
156
- logger.error(f"Error deleting memory: {e}")
157
-
158
- def drop_table(self) -> None:
159
- """Drop all memories from Redis (same as clear)"""
160
- self.clear()
161
-
162
- def table_exists(self) -> bool:
163
- """Check if any memories exist with our prefix"""
164
- try:
165
- pattern = f"{self.prefix}:*"
166
- # Use scan_iter with count=1 to efficiently check if any keys exist
167
- for _ in self.redis_client.scan_iter(match=pattern, count=1):
168
- return True
169
- return False
170
- except Exception as e:
171
- logger.error(f"Error checking if table exists: {e}")
172
- return False
173
-
174
- def clear(self) -> bool:
175
- """Clear all memories with our prefix"""
176
- try:
177
- pattern = f"{self.prefix}:*"
178
- keys_to_delete = list(self.redis_client.scan_iter(match=pattern))
179
-
180
- if keys_to_delete:
181
- self.redis_client.delete(*keys_to_delete)
182
- log_info(f"Cleared {len(keys_to_delete)} memories with prefix: {self.prefix}")
183
-
184
- return True
185
- except Exception as e:
186
- logger.error(f"Error clearing memories: {e}")
187
- return False
@@ -1,54 +0,0 @@
1
- from datetime import datetime
2
- from typing import Any, Dict, Optional
3
-
4
- from pydantic import BaseModel, ConfigDict, model_validator
5
-
6
-
7
- class MemoryRow(BaseModel):
8
- """Memory Row that is stored in the database"""
9
-
10
- # id for this memory, auto-generated if not provided
11
- id: Optional[str] = None
12
- memory: Dict[str, Any]
13
- user_id: Optional[str] = None
14
- last_updated: Optional[datetime] = None
15
-
16
- model_config = ConfigDict(from_attributes=True, arbitrary_types_allowed=True)
17
-
18
- @model_validator(mode="after")
19
- def generate_id(self) -> "MemoryRow":
20
- if self.id is None:
21
- from uuid import uuid4
22
-
23
- self.id = str(uuid4())
24
- return self
25
-
26
- def to_dict(self) -> Dict[str, Any]:
27
- _dict = self.model_dump(exclude={"last_updated"})
28
- _dict["last_updated"] = self.last_updated.isoformat() if self.last_updated else None
29
- return _dict
30
-
31
-
32
- class SummaryRow(BaseModel):
33
- """Session Summary Row that is stored in the database"""
34
-
35
- # id for this summary
36
- id: Optional[str] = None
37
- summary: Dict[str, Any]
38
- user_id: Optional[str] = None
39
- last_updated: Optional[datetime] = None
40
-
41
- model_config = ConfigDict(from_attributes=True, arbitrary_types_allowed=True)
42
-
43
- @model_validator(mode="after")
44
- def generate_id(self) -> "SummaryRow":
45
- if self.id is None:
46
- from uuid import uuid4
47
-
48
- self.id = str(uuid4())
49
- return self
50
-
51
- def to_dict(self) -> Dict[str, Any]:
52
- _dict = self.model_dump(exclude={"last_updated"})
53
- _dict["last_updated"] = self.last_updated.isoformat() if self.last_updated else None
54
- return _dict
@@ -1,209 +0,0 @@
1
- from pathlib import Path
2
- from typing import Any, Dict, List, Optional
3
-
4
- try:
5
- from sqlalchemy import (
6
- Column,
7
- DateTime,
8
- Engine,
9
- MetaData,
10
- String,
11
- Table,
12
- create_engine,
13
- delete,
14
- inspect,
15
- select,
16
- text,
17
- )
18
- from sqlalchemy.exc import SQLAlchemyError
19
- from sqlalchemy.orm import scoped_session, sessionmaker
20
- except ImportError:
21
- raise ImportError("`sqlalchemy` not installed. Please install it with `pip install sqlalchemy`")
22
-
23
- from agno.memory.v2.db.base import MemoryDb
24
- from agno.memory.v2.db.schema import MemoryRow
25
- from agno.utils.log import log_debug, log_info, logger
26
-
27
-
28
- class SqliteMemoryDb(MemoryDb):
29
- def __init__(
30
- self,
31
- table_name: str = "memory",
32
- db_url: Optional[str] = None,
33
- db_file: Optional[str] = None,
34
- db_engine: Optional[Engine] = None,
35
- ):
36
- """
37
- This class provides a memory store backed by a SQLite table.
38
-
39
- The following order is used to determine the database connection:
40
- 1. Use the db_engine if provided
41
- 2. Use the db_url
42
- 3. Use the db_file
43
- 4. Create a new in-memory database
44
-
45
- Args:
46
- table_name: The name of the table to store Agent sessions.
47
- db_url: The database URL to connect to.
48
- db_file: The database file to connect to.
49
- db_engine: The database engine to use.
50
- """
51
- self.db_file = db_file
52
- _engine: Optional[Engine] = db_engine
53
- if _engine is None and db_url is not None:
54
- _engine = create_engine(db_url)
55
- elif _engine is None and db_file is not None:
56
- # Use the db_file to create the engine
57
- db_path = Path(db_file).resolve()
58
- # Ensure the directory exists
59
- db_path.parent.mkdir(parents=True, exist_ok=True)
60
- _engine = create_engine(f"sqlite:///{db_path}")
61
- else:
62
- _engine = create_engine("sqlite://")
63
-
64
- if _engine is None:
65
- raise ValueError("Must provide either db_url, db_file or db_engine")
66
-
67
- # Database attributes
68
- self.table_name: str = table_name
69
- self.db_url: Optional[str] = db_url
70
- self.db_engine: Engine = _engine
71
- self.metadata: MetaData = MetaData()
72
- self.inspector = inspect(self.db_engine)
73
-
74
- # Database session
75
- self.Session = scoped_session(sessionmaker(bind=self.db_engine))
76
- # Database table for memories
77
- self.table: Table = self.get_table()
78
-
79
- def __dict__(self) -> Dict[str, Any]:
80
- return {
81
- "name": "SqliteMemoryDb",
82
- "table_name": self.table_name,
83
- "db_file": self.db_file,
84
- }
85
-
86
- def get_table(self) -> Table:
87
- return Table(
88
- self.table_name,
89
- self.metadata,
90
- Column("id", String, primary_key=True),
91
- Column("user_id", String, index=True),
92
- Column("memory", String),
93
- Column("created_at", DateTime, server_default=text("CURRENT_TIMESTAMP")),
94
- Column(
95
- "updated_at", DateTime, server_default=text("CURRENT_TIMESTAMP"), onupdate=text("CURRENT_TIMESTAMP")
96
- ),
97
- extend_existing=True,
98
- )
99
-
100
- def create(self) -> None:
101
- if not self.table_exists():
102
- try:
103
- log_debug(f"Creating table: {self.table_name}")
104
- self.table.create(self.db_engine, checkfirst=True)
105
- except Exception as e:
106
- logger.error(f"Error creating table '{self.table_name}': {e}")
107
- raise
108
-
109
- def memory_exists(self, memory: MemoryRow) -> bool:
110
- with self.Session() as session:
111
- stmt = select(self.table.c.id).where(self.table.c.id == memory.id)
112
- result = session.execute(stmt).first()
113
- return result is not None
114
-
115
- def read_memories(
116
- self, user_id: Optional[str] = None, limit: Optional[int] = None, sort: Optional[str] = None
117
- ) -> List[MemoryRow]:
118
- memories: List[MemoryRow] = []
119
- try:
120
- with self.Session() as session:
121
- stmt = select(self.table)
122
- if user_id is not None:
123
- stmt = stmt.where(self.table.c.user_id == user_id)
124
-
125
- if sort == "asc":
126
- stmt = stmt.order_by(self.table.c.created_at.asc())
127
- else:
128
- stmt = stmt.order_by(self.table.c.created_at.desc())
129
-
130
- if limit is not None:
131
- stmt = stmt.limit(limit)
132
-
133
- result = session.execute(stmt)
134
- for row in result:
135
- memories.append(
136
- MemoryRow(
137
- id=row.id,
138
- user_id=row.user_id,
139
- memory=eval(row.memory),
140
- last_updated=row.updated_at or row.created_at,
141
- )
142
- )
143
- except SQLAlchemyError as e:
144
- log_debug(f"Exception reading from table: {e}")
145
- log_debug(f"Table does not exist: {self.table_name}")
146
- log_debug("Creating table for future transactions")
147
- self.create()
148
- return memories
149
-
150
- def upsert_memory(self, memory: MemoryRow, create_and_retry: bool = True) -> None:
151
- try:
152
- with self.Session() as session:
153
- # Check if the memory already exists
154
- existing = session.execute(select(self.table).where(self.table.c.id == memory.id)).first()
155
-
156
- if existing:
157
- # Update existing memory
158
- stmt = (
159
- self.table.update()
160
- .where(self.table.c.id == memory.id)
161
- .values(user_id=memory.user_id, memory=str(memory.memory), updated_at=text("CURRENT_TIMESTAMP"))
162
- )
163
- else:
164
- # Insert new memory
165
- stmt = self.table.insert().values(id=memory.id, user_id=memory.user_id, memory=str(memory.memory)) # type: ignore
166
-
167
- session.execute(stmt)
168
- session.commit()
169
- except SQLAlchemyError as e:
170
- logger.error(f"Exception upserting into table: {e}")
171
- if not self.table_exists():
172
- log_info(f"Table does not exist: {self.table_name}")
173
- log_info("Creating table for future transactions")
174
- self.create()
175
- if create_and_retry:
176
- return self.upsert_memory(memory, create_and_retry=False)
177
- else:
178
- raise
179
-
180
- def delete_memory(self, memory_id: str) -> None:
181
- with self.Session() as session:
182
- stmt = delete(self.table).where(self.table.c.id == memory_id)
183
- session.execute(stmt)
184
- session.commit()
185
-
186
- def drop_table(self) -> None:
187
- if self.table_exists():
188
- log_debug(f"Deleting table: {self.table_name}")
189
- self.table.drop(self.db_engine)
190
-
191
- def table_exists(self) -> bool:
192
- log_debug(f"Checking if table exists: {self.table.name}")
193
- try:
194
- return self.inspector.has_table(self.table.name)
195
- except Exception as e:
196
- logger.error(e)
197
- return False
198
-
199
- def clear(self) -> bool:
200
- with self.Session() as session:
201
- if self.table_exists():
202
- stmt = delete(self.table)
203
- session.execute(stmt)
204
- session.commit()
205
- return True
206
-
207
- def __del__(self):
208
- # self.Session.remove()
209
- pass