agno 1.8.1__py3-none-any.whl → 2.0.0__py3-none-any.whl

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