agno 1.8.1__py3-none-any.whl → 2.0.0a1__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 (580) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +2778 -4123
  4. agno/api/agent.py +9 -65
  5. agno/api/api.py +5 -46
  6. agno/api/evals.py +6 -17
  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 +9 -64
  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 +1749 -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 +1438 -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 +888 -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 +1051 -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 +1417 -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 +298 -0
  52. agno/db/postgres/__init__.py +3 -0
  53. agno/db/postgres/postgres.py +1720 -0
  54. agno/db/postgres/schemas.py +124 -0
  55. agno/db/postgres/utils.py +281 -0
  56. agno/db/redis/__init__.py +3 -0
  57. agno/db/redis/redis.py +1371 -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 +1722 -0
  67. agno/db/singlestore/utils.py +327 -0
  68. agno/db/sqlite/__init__.py +3 -0
  69. agno/db/sqlite/schemas.py +119 -0
  70. agno/db/sqlite/sqlite.py +1680 -0
  71. agno/db/sqlite/utils.py +269 -0
  72. agno/db/utils.py +88 -0
  73. agno/eval/__init__.py +14 -0
  74. agno/eval/accuracy.py +142 -43
  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 +10 -10
  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 +1515 -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 +68 -15
  115. agno/knowledge/reader/docx_reader.py +83 -0
  116. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  117. agno/knowledge/reader/gcs_reader.py +67 -0
  118. agno/{document → knowledge}/reader/json_reader.py +30 -9
  119. agno/{document → knowledge}/reader/markdown_reader.py +36 -9
  120. agno/{document → knowledge}/reader/pdf_reader.py +79 -21
  121. agno/knowledge/reader/reader_factory.py +275 -0
  122. agno/knowledge/reader/s3_reader.py +171 -0
  123. agno/{document → knowledge}/reader/text_reader.py +31 -10
  124. agno/knowledge/reader/url_reader.py +84 -0
  125. agno/knowledge/reader/web_search_reader.py +389 -0
  126. agno/{document → knowledge}/reader/website_reader.py +37 -10
  127. agno/knowledge/reader/wikipedia_reader.py +59 -0
  128. agno/knowledge/reader/youtube_reader.py +78 -0
  129. agno/knowledge/remote_content/remote_content.py +88 -0
  130. agno/{reranker → knowledge/reranker}/base.py +1 -1
  131. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  132. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  133. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  134. agno/knowledge/types.py +30 -0
  135. agno/knowledge/utils.py +169 -0
  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 +129 -82
  141. agno/models/aws/bedrock.py +107 -175
  142. agno/models/aws/claude.py +64 -18
  143. agno/models/azure/ai_foundry.py +73 -23
  144. agno/models/base.py +347 -287
  145. agno/models/cerebras/cerebras.py +84 -27
  146. agno/models/cohere/chat.py +106 -98
  147. agno/models/google/gemini.py +100 -42
  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 +38 -144
  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 +84 -46
  158. agno/models/openai/chat.py +121 -23
  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 +14 -8
  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 +393 -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 +65 -28
  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 +33 -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 +30 -0
  184. agno/os/router.py +843 -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 +204 -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 +413 -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 +179 -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 +58 -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 +163 -0
  201. agno/os/schema.py +892 -0
  202. agno/{app/playground → os}/settings.py +8 -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/{response.py → agent.py} +144 -72
  212. agno/run/base.py +44 -58
  213. agno/run/cancel.py +83 -0
  214. agno/run/team.py +133 -77
  215. agno/run/workflow.py +537 -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 +2961 -4253
  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 +42 -22
  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 +18 -13
  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 +18 -11
  244. agno/tools/daytona.py +13 -16
  245. agno/tools/decorator.py +6 -3
  246. agno/tools/desi_vocal.py +16 -7
  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 +61 -61
  252. agno/tools/eleven_labs.py +35 -28
  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 +29 -29
  257. agno/tools/file.py +9 -8
  258. agno/tools/financial_datasets.py +25 -44
  259. agno/tools/firecrawl.py +22 -22
  260. agno/tools/function.py +68 -17
  261. agno/tools/giphy.py +22 -10
  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 +31 -19
  276. agno/tools/mem0.py +18 -12
  277. agno/tools/memori.py +14 -10
  278. agno/tools/mlx_transcribe.py +3 -2
  279. agno/tools/models/azure_openai.py +32 -14
  280. agno/tools/models/gemini.py +58 -31
  281. agno/tools/models/groq.py +29 -20
  282. agno/tools/models/nebius.py +27 -11
  283. agno/tools/models_labs.py +39 -15
  284. agno/tools/moviepy_video.py +7 -6
  285. agno/tools/neo4j.py +10 -8
  286. agno/tools/newspaper.py +7 -2
  287. agno/tools/newspaper4k.py +8 -3
  288. agno/tools/openai.py +57 -26
  289. agno/tools/openbb.py +12 -11
  290. agno/tools/opencv.py +62 -46
  291. agno/tools/openweather.py +14 -12
  292. agno/tools/pandas.py +11 -3
  293. agno/tools/postgres.py +4 -12
  294. agno/tools/pubmed.py +4 -1
  295. agno/tools/python.py +9 -22
  296. agno/tools/reasoning.py +35 -27
  297. agno/tools/reddit.py +11 -26
  298. agno/tools/replicate.py +54 -41
  299. agno/tools/resend.py +4 -1
  300. agno/tools/scrapegraph.py +15 -14
  301. agno/tools/searxng.py +10 -23
  302. agno/tools/serpapi.py +6 -3
  303. agno/tools/serper.py +13 -4
  304. agno/tools/shell.py +9 -2
  305. agno/tools/slack.py +12 -11
  306. agno/tools/sleep.py +3 -2
  307. agno/tools/spider.py +24 -4
  308. agno/tools/sql.py +7 -6
  309. agno/tools/tavily.py +6 -4
  310. agno/tools/telegram.py +12 -4
  311. agno/tools/todoist.py +11 -31
  312. agno/tools/toolkit.py +1 -1
  313. agno/tools/trafilatura.py +22 -6
  314. agno/tools/trello.py +9 -22
  315. agno/tools/twilio.py +10 -3
  316. agno/tools/user_control_flow.py +6 -1
  317. agno/tools/valyu.py +34 -5
  318. agno/tools/visualization.py +19 -28
  319. agno/tools/webbrowser.py +4 -3
  320. agno/tools/webex.py +11 -7
  321. agno/tools/website.py +15 -46
  322. agno/tools/webtools.py +12 -4
  323. agno/tools/whatsapp.py +5 -9
  324. agno/tools/wikipedia.py +20 -13
  325. agno/tools/x.py +14 -13
  326. agno/tools/yfinance.py +13 -40
  327. agno/tools/youtube.py +26 -20
  328. agno/tools/zendesk.py +7 -2
  329. agno/tools/zep.py +10 -7
  330. agno/tools/zoom.py +10 -9
  331. agno/utils/common.py +1 -19
  332. agno/utils/events.py +95 -118
  333. agno/utils/knowledge.py +29 -0
  334. agno/utils/log.py +2 -2
  335. agno/utils/mcp.py +11 -5
  336. agno/utils/media.py +39 -0
  337. agno/utils/message.py +12 -1
  338. agno/utils/models/claude.py +6 -4
  339. agno/utils/models/mistral.py +8 -7
  340. agno/utils/models/schema_utils.py +3 -3
  341. agno/utils/pprint.py +33 -32
  342. agno/utils/print_response/agent.py +779 -0
  343. agno/utils/print_response/team.py +1565 -0
  344. agno/utils/print_response/workflow.py +1451 -0
  345. agno/utils/prompts.py +14 -14
  346. agno/utils/reasoning.py +87 -0
  347. agno/utils/response.py +42 -42
  348. agno/utils/string.py +8 -22
  349. agno/utils/team.py +50 -0
  350. agno/utils/timer.py +2 -2
  351. agno/vectordb/base.py +33 -21
  352. agno/vectordb/cassandra/cassandra.py +287 -23
  353. agno/vectordb/chroma/chromadb.py +482 -59
  354. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  355. agno/vectordb/couchbase/couchbase.py +309 -29
  356. agno/vectordb/lancedb/lance_db.py +360 -21
  357. agno/vectordb/langchaindb/__init__.py +5 -0
  358. agno/vectordb/langchaindb/langchaindb.py +145 -0
  359. agno/vectordb/lightrag/__init__.py +5 -0
  360. agno/vectordb/lightrag/lightrag.py +374 -0
  361. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  362. agno/vectordb/milvus/milvus.py +242 -32
  363. agno/vectordb/mongodb/mongodb.py +200 -24
  364. agno/vectordb/pgvector/pgvector.py +319 -37
  365. agno/vectordb/pineconedb/pineconedb.py +221 -27
  366. agno/vectordb/qdrant/qdrant.py +334 -14
  367. agno/vectordb/singlestore/singlestore.py +286 -29
  368. agno/vectordb/surrealdb/surrealdb.py +187 -7
  369. agno/vectordb/upstashdb/upstashdb.py +342 -26
  370. agno/vectordb/weaviate/weaviate.py +227 -165
  371. agno/workflow/__init__.py +17 -13
  372. agno/workflow/{v2/condition.py → condition.py} +135 -32
  373. agno/workflow/{v2/loop.py → loop.py} +115 -28
  374. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  375. agno/workflow/{v2/router.py → router.py} +133 -32
  376. agno/workflow/{v2/step.py → step.py} +200 -42
  377. agno/workflow/{v2/steps.py → steps.py} +147 -66
  378. agno/workflow/types.py +482 -0
  379. agno/workflow/workflow.py +2394 -696
  380. agno-2.0.0a1.dist-info/METADATA +355 -0
  381. agno-2.0.0a1.dist-info/RECORD +514 -0
  382. agno/agent/metrics.py +0 -107
  383. agno/api/app.py +0 -35
  384. agno/api/playground.py +0 -92
  385. agno/api/schemas/app.py +0 -12
  386. agno/api/schemas/playground.py +0 -22
  387. agno/api/schemas/user.py +0 -35
  388. agno/api/schemas/workspace.py +0 -46
  389. agno/api/user.py +0 -160
  390. agno/api/workflows.py +0 -33
  391. agno/api/workspace.py +0 -175
  392. agno/app/agui/__init__.py +0 -3
  393. agno/app/agui/app.py +0 -17
  394. agno/app/agui/sync_router.py +0 -120
  395. agno/app/base.py +0 -186
  396. agno/app/discord/__init__.py +0 -3
  397. agno/app/fastapi/__init__.py +0 -3
  398. agno/app/fastapi/app.py +0 -107
  399. agno/app/fastapi/async_router.py +0 -457
  400. agno/app/fastapi/sync_router.py +0 -448
  401. agno/app/playground/app.py +0 -228
  402. agno/app/playground/async_router.py +0 -1050
  403. agno/app/playground/deploy.py +0 -249
  404. agno/app/playground/operator.py +0 -183
  405. agno/app/playground/schemas.py +0 -220
  406. agno/app/playground/serve.py +0 -55
  407. agno/app/playground/sync_router.py +0 -1042
  408. agno/app/playground/utils.py +0 -46
  409. agno/app/settings.py +0 -15
  410. agno/app/slack/__init__.py +0 -3
  411. agno/app/slack/app.py +0 -19
  412. agno/app/slack/sync_router.py +0 -92
  413. agno/app/utils.py +0 -54
  414. agno/app/whatsapp/__init__.py +0 -3
  415. agno/app/whatsapp/app.py +0 -15
  416. agno/app/whatsapp/sync_router.py +0 -197
  417. agno/cli/auth_server.py +0 -249
  418. agno/cli/config.py +0 -274
  419. agno/cli/console.py +0 -88
  420. agno/cli/credentials.py +0 -23
  421. agno/cli/entrypoint.py +0 -571
  422. agno/cli/operator.py +0 -357
  423. agno/cli/settings.py +0 -96
  424. agno/cli/ws/ws_cli.py +0 -817
  425. agno/constants.py +0 -13
  426. agno/document/__init__.py +0 -5
  427. agno/document/chunking/semantic.py +0 -45
  428. agno/document/chunking/strategy.py +0 -31
  429. agno/document/reader/__init__.py +0 -5
  430. agno/document/reader/base.py +0 -47
  431. agno/document/reader/docx_reader.py +0 -60
  432. agno/document/reader/gcs/pdf_reader.py +0 -44
  433. agno/document/reader/s3/pdf_reader.py +0 -59
  434. agno/document/reader/s3/text_reader.py +0 -63
  435. agno/document/reader/url_reader.py +0 -59
  436. agno/document/reader/youtube_reader.py +0 -58
  437. agno/embedder/__init__.py +0 -5
  438. agno/embedder/langdb.py +0 -80
  439. agno/embedder/mistral.py +0 -82
  440. agno/embedder/openai.py +0 -78
  441. agno/file/__init__.py +0 -5
  442. agno/file/file.py +0 -16
  443. agno/file/local/csv.py +0 -32
  444. agno/file/local/txt.py +0 -19
  445. agno/infra/app.py +0 -240
  446. agno/infra/base.py +0 -144
  447. agno/infra/context.py +0 -20
  448. agno/infra/db_app.py +0 -52
  449. agno/infra/resource.py +0 -205
  450. agno/infra/resources.py +0 -55
  451. agno/knowledge/agent.py +0 -702
  452. agno/knowledge/arxiv.py +0 -33
  453. agno/knowledge/combined.py +0 -36
  454. agno/knowledge/csv.py +0 -144
  455. agno/knowledge/csv_url.py +0 -124
  456. agno/knowledge/document.py +0 -223
  457. agno/knowledge/docx.py +0 -137
  458. agno/knowledge/firecrawl.py +0 -34
  459. agno/knowledge/gcs/__init__.py +0 -0
  460. agno/knowledge/gcs/base.py +0 -39
  461. agno/knowledge/gcs/pdf.py +0 -125
  462. agno/knowledge/json.py +0 -137
  463. agno/knowledge/langchain.py +0 -71
  464. agno/knowledge/light_rag.py +0 -273
  465. agno/knowledge/llamaindex.py +0 -66
  466. agno/knowledge/markdown.py +0 -154
  467. agno/knowledge/pdf.py +0 -164
  468. agno/knowledge/pdf_bytes.py +0 -42
  469. agno/knowledge/pdf_url.py +0 -148
  470. agno/knowledge/s3/__init__.py +0 -0
  471. agno/knowledge/s3/base.py +0 -64
  472. agno/knowledge/s3/pdf.py +0 -33
  473. agno/knowledge/s3/text.py +0 -34
  474. agno/knowledge/text.py +0 -141
  475. agno/knowledge/url.py +0 -46
  476. agno/knowledge/website.py +0 -179
  477. agno/knowledge/wikipedia.py +0 -32
  478. agno/knowledge/youtube.py +0 -35
  479. agno/memory/agent.py +0 -423
  480. agno/memory/classifier.py +0 -104
  481. agno/memory/db/__init__.py +0 -5
  482. agno/memory/db/base.py +0 -42
  483. agno/memory/db/mongodb.py +0 -189
  484. agno/memory/db/postgres.py +0 -203
  485. agno/memory/db/sqlite.py +0 -193
  486. agno/memory/memory.py +0 -22
  487. agno/memory/row.py +0 -36
  488. agno/memory/summarizer.py +0 -201
  489. agno/memory/summary.py +0 -19
  490. agno/memory/team.py +0 -415
  491. agno/memory/v2/__init__.py +0 -2
  492. agno/memory/v2/db/__init__.py +0 -1
  493. agno/memory/v2/db/base.py +0 -42
  494. agno/memory/v2/db/firestore.py +0 -339
  495. agno/memory/v2/db/mongodb.py +0 -196
  496. agno/memory/v2/db/postgres.py +0 -214
  497. agno/memory/v2/db/redis.py +0 -187
  498. agno/memory/v2/db/schema.py +0 -54
  499. agno/memory/v2/db/sqlite.py +0 -209
  500. agno/memory/v2/manager.py +0 -437
  501. agno/memory/v2/memory.py +0 -1097
  502. agno/memory/v2/schema.py +0 -55
  503. agno/memory/v2/summarizer.py +0 -215
  504. agno/memory/workflow.py +0 -38
  505. agno/models/ollama/tools.py +0 -430
  506. agno/models/qwen/__init__.py +0 -5
  507. agno/playground/__init__.py +0 -10
  508. agno/playground/deploy.py +0 -3
  509. agno/playground/playground.py +0 -3
  510. agno/playground/serve.py +0 -3
  511. agno/playground/settings.py +0 -3
  512. agno/reranker/__init__.py +0 -0
  513. agno/run/v2/__init__.py +0 -0
  514. agno/run/v2/workflow.py +0 -567
  515. agno/storage/__init__.py +0 -0
  516. agno/storage/agent/__init__.py +0 -0
  517. agno/storage/agent/dynamodb.py +0 -1
  518. agno/storage/agent/json.py +0 -1
  519. agno/storage/agent/mongodb.py +0 -1
  520. agno/storage/agent/postgres.py +0 -1
  521. agno/storage/agent/singlestore.py +0 -1
  522. agno/storage/agent/sqlite.py +0 -1
  523. agno/storage/agent/yaml.py +0 -1
  524. agno/storage/base.py +0 -60
  525. agno/storage/dynamodb.py +0 -673
  526. agno/storage/firestore.py +0 -297
  527. agno/storage/gcs_json.py +0 -261
  528. agno/storage/in_memory.py +0 -234
  529. agno/storage/json.py +0 -237
  530. agno/storage/mongodb.py +0 -328
  531. agno/storage/mysql.py +0 -685
  532. agno/storage/postgres.py +0 -682
  533. agno/storage/redis.py +0 -336
  534. agno/storage/session/__init__.py +0 -16
  535. agno/storage/session/agent.py +0 -64
  536. agno/storage/session/team.py +0 -63
  537. agno/storage/session/v2/__init__.py +0 -5
  538. agno/storage/session/workflow.py +0 -61
  539. agno/storage/singlestore.py +0 -606
  540. agno/storage/sqlite.py +0 -646
  541. agno/storage/workflow/__init__.py +0 -0
  542. agno/storage/workflow/mongodb.py +0 -1
  543. agno/storage/workflow/postgres.py +0 -1
  544. agno/storage/workflow/sqlite.py +0 -1
  545. agno/storage/yaml.py +0 -241
  546. agno/tools/thinking.py +0 -73
  547. agno/utils/defaults.py +0 -57
  548. agno/utils/filesystem.py +0 -39
  549. agno/utils/git.py +0 -52
  550. agno/utils/json_io.py +0 -30
  551. agno/utils/load_env.py +0 -19
  552. agno/utils/py_io.py +0 -19
  553. agno/utils/pyproject.py +0 -18
  554. agno/utils/resource_filter.py +0 -31
  555. agno/workflow/v2/__init__.py +0 -21
  556. agno/workflow/v2/types.py +0 -357
  557. agno/workflow/v2/workflow.py +0 -3312
  558. agno/workspace/__init__.py +0 -0
  559. agno/workspace/config.py +0 -325
  560. agno/workspace/enums.py +0 -6
  561. agno/workspace/helpers.py +0 -52
  562. agno/workspace/operator.py +0 -757
  563. agno/workspace/settings.py +0 -158
  564. agno-1.8.1.dist-info/METADATA +0 -982
  565. agno-1.8.1.dist-info/RECORD +0 -566
  566. agno-1.8.1.dist-info/entry_points.txt +0 -3
  567. /agno/{app → db/migrations}/__init__.py +0 -0
  568. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  569. /agno/{cli → integrations}/__init__.py +0 -0
  570. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  571. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  572. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  573. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  574. /agno/{app → os/interfaces}/slack/security.py +0 -0
  575. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  576. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  577. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  578. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/WHEEL +0 -0
  579. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
  580. {agno-1.8.1.dist-info → agno-2.0.0a1.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